рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдПрдХ рдмрд╣реБрдд рд╣реА рд╕реБрдВрджрд░ рднрд╛рд╖рд╛ рд╣реИред рдЗрд╕рдХреЗ рд╢рд╕реНрддреНрд░рд╛рдЧрд╛рд░ рдореЗрдВ рд╡рд╣ рд╕рдм рдХреБрдЫ рд╣реИ рдЬреЛ рдЙрдЪреНрдЪ рдЧреБрдгрд╡рддреНрддрд╛ рд╡рд╛рд▓реЗ рд╡рд┐рдХрд╛рд╕ рдХреЗ рд▓рд┐рдП рдЖрд╡рд╢реНрдпрдХ рд╣реИред рдФрд░ рдЕрдЧрд░ рдЕрдЪрд╛рдирдХ, рдХреЛрдИ рдЬрд╛рд╡рд╛рд╕реНрдХреНрд░рд┐рдкреНрдЯ рдХреЗ рд╕рд╛рде рд╕реЗрдХреНрд╕-рдирд╛рдЯрдХреАрдп рд╕реНрдХреЗрдЪ рд╕реЗ рдкрд░рд┐рдЪрд┐рдд рд╣реИ, рддреЛ рдореИрдВ рд╕рдордЭреВрдВрдЧрд╛ред рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдореЗрдВ рдХрдИ рдорд╛рдиреНрдпрддрд╛рдУрдВ, рдЕрдкреНрд░рддреНрдпрд╛рд╢рд┐рдд рд╡рд╛рдХреНрдпрд╡рд┐рдиреНрдпрд╛рд╕, рдФрд░ рд░рдордгреАрдп рдбрд┐рдЬрд╛рдЗрди рд╣реИрдВ рдЬреЛ рдЗрд╕рдХреА рд╕реБрдВрджрд░рддрд╛, рд░реВрдк рдкрд░ рдЬреЛрд░ рджреЗрддреЗ рд╣реИрдВ рдФрд░ рдЗрд╕реЗ рдирдП рдЕрд░реНрде рдХреЗ рд╕рд╛рде рднрд░рддреЗ рд╣реИрдВред рдЖрдЬ рд╣рдо рдЙрдирдХреЗ рдмрд╛рд░реЗ рдореЗрдВ, рдЗрди рдорд╛рдиреНрдпрддрд╛рдУрдВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ, рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рдХреЗ рдЬрд╛рджреВ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдмрд╛рдд рдХрд░ рд░рд╣реЗ рд╣реИрдВред рдХреМрди рдкрд░рд╡рд╛рд╣ рдХрд░рддрд╛ рд╣реИ, рд╕реНрд╡рд╛рдЧрдд рд╣реИред
рдереЛрдбрд╝рд╛ рд╕рдЪ
рд╕рддреНрдп N резред
рдЕрдзрд┐рдХрд╛рдВрд╢ рдбрд┐рдЬрд╝рд╛рдЗрди рдФрд░ рдЕрдирдкреЗрдХреНрд╖рд┐рдд рдиреАрдЪреЗ рдЙрд▓реНрд▓рд┐рдЦрд┐рдд рд╣реИрдВ, рдореИрдВрдиреЗ рд╕рдмрд╕реЗ рдкрд╣рд▓реЗ рдЕрдкрдиреА рдирдЬрд╝рд░ рд╕реНрдЯреИрдХ рдУрд╡рд░рдлреНрд▓реЛ рдХреЗ рдкреГрд╖реНрдареЛрдВ рдкрд░ рд░рдЦреА, рдЬреАрдердм рдпрд╛ рдЦреБрдж рдХрд╛ рдЖрд╡рд┐рд╖реНрдХрд╛рд░ рдХрд┐рдпрд╛ред рдФрд░ рдЙрд╕рдХреЗ рдмрд╛рдж рд╣реА рдЗрд╕ рдкрд░
рдзреНрдпрд╛рди рдЧрдпрд╛ - рдпрд╣ рд╕рдм
рдпрд╣рд╛рдБ рдпрд╛
рдпрд╣рд╛рдБ рд╣реИ ред рдЗрд╕рд▓рд┐рдП, рдореИрдВ рдЖрдкрдХреЛ рдкрд╣рд▓реЗ рд╕реЗ рд╕рдордЭрджрд╛рд░реА рдХреЗ рд╕рд╛рде рдЗрд▓рд╛рдЬ рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП рдХрд╣рддрд╛ рд╣реВрдВ рдпрджрд┐ рдЙрд▓реНрд▓рд┐рдЦрд┐рдд рдирд┐рд╖реНрдХрд░реНрд╖ рдЖрдкрдХреЛ рд╕рд╣реА рд▓рдЧрддреЗ рд╣реИрдВред
рд╕рдЪреНрдЪрд╛ N2ред
рдХреБрдЫ рдбрд┐рдЬрд╛рдЗрдиреЛрдВ рдХрд╛ рд╡реНрдпрд╛рд╡рд╣рд╛рд░рд┐рдХ рдореВрд▓реНрдп 0 рд╣реИред
рд╕рдЪреНрдЪрд╛ N3ред
рдЙрджрд╛рд╣рд░рдгреЛрдВ рдХрд╛ рдкрд░реАрдХреНрд╖рдг tsc рд╕рдВрд╕реНрдХрд░рдг 3.4.5 рдФрд░ рд▓рдХреНрд╖реНрдп es5 рдХреЗ рддрд╣рдд рдХрд┐рдпрд╛ рдЧрдпрд╛ред рдмрд╕ рдорд╛рдорд▓реЗ рдореЗрдВ, рдмрд┐рдЧрд╛рдбрд╝рдиреЗ рд╡рд┐рдиреНрдпрд╛рд╕ рдХреЗ рддрд╣рдд
tsconfig.json{
"рд╕рдВрдХрд▓рдирдХрд░реНрддрд╛": {
"рдЖрдЙрдЯрдлрд╛рдЗрд▓": "./getget/result.js",
"рдореЙрдбреНрдпреВрд▓": "рдПрдордб",
"рд▓рдХреНрд╖реНрдп": "es5",
"рдШреЛрд╖рдгрд╛": рд╕рдЪ рд╣реИ,
"NoImplicitAny": рд╕рдЪ рд╣реИ,
"NoImplicitReturns": рд╕рдЪ рд╣реИ,
"рд╕реНрдЯреНрд░рд┐рдХреНрдЯрдирдХреБрд▓ рдЪреЗрдХ": рд╕рдЪ,
"StrictPropertyInitialization": рд╕рдЪ рд╣реИ,
"рдкреНрд░рд╛рдпреЛрдЧрд┐рдХрд╡рд┐рдХрд╛рд╕рдХрд░реНрддрд╛": рд╕рдЪ рд╣реИ,
"рдПрдорд┐рдЯрдбреЗрдХреЛрд░реЗрдЯрд░рдорд╛рдЯрд╛рдбрд╛рдЯрд╛": рд╕рдЪ рд╣реИ,
"PreserveConstEnums": рд╕рдЪ рд╣реИ,
"NoResolve": рд╕рдЪ рд╣реИ,
"SourceMap": рд╕рдЪ рд╣реИ,
"рдЗрдирд▓рд╛рдЗрди рд╕реНрд░реЛрдд": рд╕рдЪ рд╣реИ
}
"рд╢рд╛рдорд┐рд▓ рдХрд░реЗрдВ": [
"./Src"
]
}
рдХрд╛рд░реНрдпрд╛рдиреНрд╡рдпрди рдФрд░ рд╡рдВрд╢рд╛рдиреБрдХреНрд░рдо
рдЦреЛрдЬреЗрдВ : рдФрдЬрд╛рд░ рдЕрдиреБрднрд╛рдЧ рдореЗрдВ рдЖрдк рдЗрдВрдЯрд░рдлреЗрд╕, рдкреНрд░рдХрд╛рд░ рдФрд░
рдХрдХреНрд╖рд╛рдПрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рд╣рдо рдмрд╛рдж рдореЗрдВ рд░реБрдЪрд┐ рд░рдЦрддреЗ рд╣реИрдВред
рдпрд╣рд╛рдБ рд╡рд┐рд╡рд░рдг
abstract class ClassA { abstract getA(): string; } abstract class ClassB { abstract getB(): string; } // , tsc abstract class ClassC implements ClassA, ClassB { // ^ , implements . abstract getA(): string; abstract getB(): string; }
рдореБрдЭреЗ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдбреЗрд╡рд▓рдкрд░реНрд╕ рдиреЗ рдХреНрд▓рд╛рд╕ рдХреАрд╡рд░реНрдб рдХреЗ рдорд╛рдзреНрдпрдо рд╕реЗ рдирд┐рд╖реНрдкрд╛рджрд┐рдд 'рд╕рдЦреНрдд рдЕрдиреБрдмрдВрдзреЛрдВ' рдХрд╛ рдзреНрдпрд╛рди рд░рдЦрд╛ред рдЗрд╕рдХреЗ рдЕрд▓рд╛рд╡рд╛, рдХрдХреНрд╖рд╛рдПрдВ рдЕрдореВрд░реНрдд рд╣реЛрдиреЗ рдХреА рдЬрд░реВрд░рдд рдирд╣реАрдВ рд╣реИред
рдЦреЛрдЬреЗрдВ : рдПрдХреНрд╕рдЯреЗрдВрд╢рдиреНрд╕ рдХреЛ рдПрдХреНрд╕рдЯреЗрдВрдбреЗрдб рд╕реЗрдХреНрд╢рди рдореЗрдВ рдЕрдиреБрдорддрд┐ рджреА рдЧрдИ рд╣реИред
рд╡рд┐рд╡рд░рдг ред рдпрджрд┐ рдПрдХ рдкреНрд░рд╢реНрди рдкреВрдЫрдирд╛ рд╣реИ - рдХреНрдпрд╛ 2 рд╡рд░реНрдЧреЛрдВ рд╕реЗ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рд╕рдВрднрд╡ рд╣реИ, рддреЛ рдФрдкрдЪрд╛рд░рд┐рдХ рдЙрддреНрддрд░ рдирд╣реАрдВ рд╣реИред рд▓реЗрдХрд┐рди рдЕрдЧрд░ рдЖрдк рдХрд╛ рдорддрд▓рдм рд╣реИ рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдирд┐рд░реНрдпрд╛рдд рдХрд░рдирд╛ - рд╣рд╛рдБред
class One { one = "__one__"; getOne(): string { return "one"; } } class Two { two = "__two__"; getTwo(): string { return "two"; } } // , : IDE ( ) . class BothTogether extends mix(One, Two) { // ^ , extends info(): string { return "BothTogether: " + this.getOne() + " and " + this.getTwo() + ", one: " + this.one + ", two: " + this.two; // ^ IDE ^ } } type FaceType<T> = { [K in keyof T]: T[K]; }; type Constructor<T> = { // prototype: T & {[key: string]: any}; new(): T; }; // TODO: , . function mix<O, T, Mix = O & T>(o: Constructor<O>, t: Constructor<T>): FaceType<Mix> & Constructor<Mix> { function MixinClass(...args: any) { o.apply(this, args); t.apply(this, args); } const ignoreNamesFilter = (name: string) => ["constructor"].indexOf(name) === -1; [o, t].forEach(baseCtor => { Object.getOwnPropertyNames(baseCtor.prototype).filter(ignoreNamesFilter).forEach(name => { MixinClass.prototype[name] = baseCtor.prototype[name]; }); }); return MixinClass as any; } const bt = new BothTogether(); window.console.log(bt.info()); // >> BothTogether: one and two, one: __one__, two: __two__
рдЦреЛрдЬреЗрдВ : рдПрдХ
рдЧрд╣рд░реА рдФрд░ рдПрдХ рд╣реА рд╕рдордп рдореЗрдВ рдЕрд░реНрдерд╣реАрди рдЕрдирд╛рдоред
const lass = class extends class extends class extends class extends class {} {} {} {} {};
рдФрд░ 4 рдХреЗ рд╕рд╛рде рд╢рдмреНрдж рд╡рд░реНрдЧ рдХреМрди рд▓рд┐рдЦреЗрдЧрд╛ рдЬреЛ рдЙрдкрд░реЛрдХреНрдд рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рд╡рд┐рд╕реНрддреГрдд рд╣реИ?
рдЕрдЧрд░ рдРрд╕рд╛ рд╣реИ // tslint:disable const Class = class Class extends class Class extends class Class extends class Class extends class Class {} {} {} {} {};
рдФрд░ рдЕрдзрд┐рдХ?
рдЗрд╕ рддрд░рд╣ // tslint:disable const lass = class Class<Class> extends class Class extends class Class extends class Class extends class Class {} {} {} {} {};
рдЦреИрд░, рдЖрдк рдЗрд╕реЗ рдкреНрд░рд╛рдкреНрдд рдХрд░рддреЗ рд╣реИрдВ - рдпрд╣ рд╕рд┐рд░реНрдл рдХрдХреНрд╖рд╛ рд╣реИ!
рд╡рд┐рд╕реНрдордпрд╛рджрд┐рдмреЛрдзрдХ рдорд╛рд░реНрдХ - рдЕрд╕реАрдорд┐рдд рдСрдкрд░реЗрдЯрд░ рдФрд░ рд╕рдВрд╢реЛрдзрдХ
рдпрджрд┐ рдЖрдк рдХрдбрд╝рд╛рдИ рд╕реЗ рдЙрдкрдпреЛрдЧ рдирд╣реАрдВ рдХрд░рддреЗ рд╣реИрдВ рддреЛ рдирд┐рд╢реБрд▓реНрдХ рдЬрд╛рдВрдЪ рдФрд░ рдХрдбрд╝рд╛рдИ рд╕реЗ рдЬрд╛рдВрдЪ рдХрд░реЗрдВред
рддрдм рд╕рдмрд╕реЗ рдЕрдзрд┐рдХ рд╕рдВрднрд╛рд╡рдирд╛ рд╣реИ рдХрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рд╕реЗ рдирд┐рдХрд▓реЗ рд╡рд┐рд╕реНрдордпрд╛рджрд┐рдмреЛрдзрдХ рдЪрд┐рд╣реНрди рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдЬреНрдЮрд╛рди ... рдореБрдЦреНрдп рдЙрджреНрджреЗрд╢реНрдп рдХреЗ рдЕрд▓рд╛рд╡рд╛, 2 рдФрд░ рднреВрдорд┐рдХрд╛рдПрдВ рдЗрд╕реЗ рд╕реМрдВрдкреА рдЧрдИ рд╣реИрдВред
рдЦреЛрдЬреЗрдВ :
рдЧреИрд░-рдЕрд╢рдХреНрдд рд╕рдВрдЪрд╛рд▓рдХ рдХреЗ рд░реВрдк рдореЗрдВ рд╡рд┐рд╕реНрдордпрд╛рджрд┐рдмреЛрдзрдХ рдЪрд┐рд╣реНрди
рдпрд╣ рдСрдкрд░реЗрдЯрд░ рдЖрдкрдХреЛ рд╕рдВрд░рдЪрдирд╛ рдХреНрд╖реЗрддреНрд░ рддрдХ рдкрд╣реБрдВрдЪрдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдЬреЛ рд╢реВрдиреНрдп рдХреЗ рд▓рд┐рдП рдЬрд╛рдВрдЪ рдХреЗ рдмрд┐рдирд╛ рд╢реВрдиреНрдп рд╣реЛ рд╕рдХрддрд╛ рд╣реИред рдПрдХ рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдХреЗ рд╕рд╛рде рдПрдХ рдЙрджрд╛рд╣рд░рдг:
// --strictNullChecks type OptType = { maybe?: { data: string; }; }; // ... function process(optType: OptType) { completeOptFields(optType); // , completeOptFields . window.console.log(optType.maybe!.data); // ^ - , null // !, tsc: Object is possibly 'undefined' } function completeOptFields(optType: OptType) { if (!optType.maybe) { optType.maybe = { data: "some default info" }; } }
рдХреБрд▓ рдореЗрдВ, рдпрд╣ рдСрдкрд░реЗрдЯрд░ рдЖрдкрдХреЛ рдХреЛрдб рдореЗрдВ рдЕрд╢рдХреНрддрддрд╛ рдХреЗ рд▓рд┐рдП рдЕрдирд╛рд╡рд╢реНрдпрдХ рдЬрд╛рдБрдЪ рдХреЛ рд╣рдЯрд╛рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрддрд╛ рд╣реИ, рдЕрдЧрд░ рд╣рдореЗрдВ рдпрдХреАрди рд╣реИ ...
рдЦреЛрдЬреЗрдВ :
рдирд┐рд╢реНрдЪрд┐рдд рдЪрд┐рд╣реНрди рдХреЗ рд░реВрдк рдореЗрдВ рд╡рд┐рд╕реНрдордпрд╛рджрд┐рдмреЛрдзрдХ рдЪрд┐рд╣реНрди
рд╕рдВрд╢реЛрдзрди рд╕рдВрд╢реЛрдзрдХрдпрд╣ рд╕рдВрд╢реЛрдзрдХ рд╣рдореЗрдВ рдмрд╛рдж рдореЗрдВ рдХреЛрдб рдореЗрдВ рдХрд╣реАрдВ рд╕рдЦреНрдд рд╡рд░реНрдЧрдкреНрд░рдорд╛рдгреАрдХрд░рдг рд╕рдВрдХрд▓рди рд╡рд┐рдХрд▓реНрдк рдХреЗ рд╕рд╛рде, рд╡рд░реНрдЧ рдХреА рд╕рдВрдкрддреНрддрд┐ рдХреЛ рдЖрд░рдВрдн рдХрд░рдиреЗ рдХреА рдЕрдиреБрдорддрд┐ рджреЗрдЧрд╛ред рдПрдХ рд╕реНрдкрд╖реНрдЯреАрдХрд░рдг рдХреЗ рд╕рд╛рде рдПрдХ рдЙрджрд╛рд╣рд░рдг:
// --strictPropertyInitialization class Field { foo!: number; // ^ // Notice this '!' modifier. // This is the "definite assignment assertion" constructor() { this.initialize(); } initialize() { this.foo = 0; // ^ } }
рд▓реЗрдХрд┐рди рд╡рд┐рд╕реНрдордпрд╛рджрд┐рдмреЛрдзрдХ рдмрд┐рдВрджреБ рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рдпрд╣ рд╕рднреА рдорд┐рдиреА-рдЧрдгрдирд╛ рд╣рд╛рд╕реНрдп рдХреЗ рдПрдХ рдкрд▓ рдХреЗ рдмрд┐рдирд╛ рд╕рдордЭ рдореЗрдВ рдирд╣реАрдВ рдЖрдПрдЧреАред
рдкреНрд░рд╢реНрди: рдХреНрдпрд╛ рдЖрдкрдХреЛ рд▓рдЧрддрд╛ рд╣реИ рдХрд┐ рдирд┐рдореНрдирд▓рд┐рдЦрд┐рдд рдЕрднрд┐рд╡реНрдпрдХреНрддрд┐ рд╕рдВрдХрд▓рд┐рдд рд╣реЛрдЧреА?
// --strictNullChecks type OptType = { maybe?: { data: string; }; }; function process(optType: OptType) { if (!!!optType.maybe!!!) { window.console.log("Just for fun"); } window.console.log(optType.maybe!!!!.data); }
рдЬрд╡рд╛рдм рд╣реИрд╣рд╛рдВ
рдкреНрд░рдХрд╛рд░
рд╣рд░ рдХреЛрдИ рдЬреЛ рдЬрдЯрд┐рд▓ рдкреНрд░рдХрд╛рд░ рд▓рд┐рдЦрддрд╛ рд╣реИ, рдмрд╣реБрдд рд╕реА рджрд┐рд▓рдЪрд╕реНрдк рдмрд╛рддреЛрдВ рдХреЛ рдЬрд╛рдирддрд╛ рд╣реИред рддреЛ рдореИрдВ рднрд╛рдЧреНрдпрд╢рд╛рд▓реА рд╣реЛ рдЧрдпрд╛ред
рдЦреЛрдЬреЗрдВ : рдПрдХ рдЙрдкрдкреНрд░рдХрд╛рд░ рдореБрдЦреНрдп рдХреНрд╖реЗрддреНрд░ рдХреЗ рдХреНрд╖реЗрддреНрд░ рдХреЗ рдирд╛рдо рд╕реЗ рд╕рдВрджрд░реНрднрд┐рдд рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред
type Person = { id: string; name: string; address: { city: string; street: string; house: string; } }; type Address = Person["address"];
рдЬрдм рдЖрдк рд╕реНрд╡рдпрдВ рд▓рд┐рдЦрддреЗ рд╣реИрдВ, рддреЛ рдпрд╣ рдШреЛрд╖рдгрд╛ рджреГрд╖реНрдЯрд┐рдХреЛрдг рд╢рд╛рдпрдж рд╣реА рд╕рдордЭ рдореЗрдВ рдЖрддрд╛ рд╣реИред рд▓реЗрдХрд┐рди рдРрд╕рд╛ рд╣реЛрддрд╛ рд╣реИ рдХрд┐ рдПрдХ рдкреНрд░рдХрд╛рд░ рдмрд╛рд╣рд░реА рдкреБрд╕реНрддрдХрд╛рд▓рдп рд╕реЗ рдЖрддрд╛ рд╣реИ, рд▓реЗрдХрд┐рди рдПрдХ рдЙрдкрдкреНрд░рдХрд╛рд░ рдирд╣реАрдВ рд╣реЛрддрд╛ рд╣реИред
рдХреЛрдб рдкрдардиреАрдпрддрд╛ рдореЗрдВ рд╕реБрдзрд╛рд░ рдХреЗ рд▓рд┐рдП рдПрдХ рдЙрдкрдкреНрд░рдХрд╛рд░ рдЪрд╛рд▓ рдХрд╛ рднреА рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛ рд╕рдХрддрд╛ рд╣реИред рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рдЖрдкрдХреЗ рдкрд╛рд╕ рдПрдХ рд╕рд╛рдорд╛рдиреНрдп рдкреНрд░рдХрд╛рд░ рдХреЗ рд╕рд╛рде рдПрдХ рдЖрдзрд╛рд░ рд╡рд░реНрдЧ рд╣реИ рдЬреЛ рдХрдХреНрд╖рд╛рдПрдВ рд╡рд┐рд░рд╛рд╕рдд рдореЗрдВ рдорд┐рд▓реА рд╣реИрдВред рдиреАрдЪреЗ рджрд┐рдП рдЧрдП рдЙрджрд╛рд╣рд░рдг рдореЗрдВ рдмрддрд╛рдпрд╛ рдЧрдпрд╛ рд╣реИ рдХрд┐ рдХреНрдпрд╛ рдХрд╣рд╛ рдЧрдпрд╛ рд╣реИред
class BaseDialog<In, Out> { show(params: In): Out {/** . return ... */ } } // - class PersonDialogOld extends BaseDialog<Person[], string> {/** */} // class PersonDialog extends BaseDialog<Person[], Person["id"]> {/** */}
рдвреВрдБрдвреЗрдВ : рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдкреНрд░рдХрд╛рд░ рдкреНрд░рдгрд╛рд▓реА рдХреА рдорджрдж рд╕реЗ рд╡рд╛рдВрдЫрд┐рдд рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЗ рдХрд╡рд░реЗрдЬ рдХреЗ рд╕рд╛рде рдЙрддреНрдкрдиреНрди рдкреНрд░рдХрд╛рд░реЛрдВ рдХрд╛ рдПрдХ рд╕рдВрдпреЛрдЬрди рд╕реЗрдЯ рдкреНрд░рд╛рдкреНрдд рдХрд░рдирд╛ рд╕рдВрднрд╡ рд╣реИред рдХрд╣рдирд╛ рдореБрд╢реНрдХрд┐рд▓ рд╣реИ, рдореБрдЭреЗ рдкрддрд╛ рд╣реИред рдореИрдВрдиреЗ рдЗрд╕ рд╕реВрддреНрд░реАрдХрд░рдг рдХреЗ рдмрд╛рд░реЗ рдореЗрдВ рд▓рдВрдмреЗ рд╕рдордп рддрдХ рд╕реЛрдЪрд╛ред рдореИрдВ рдЖрдкрдХреЛ рдмрд┐рд▓реНрдбрд░ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХрд╛ рдПрдХ рдЙрджрд╛рд╣рд░рдг рджрд┐рдЦрд╛рдКрдВрдЧрд╛, рдЬреЛ рд╕рдмрд╕реЗ рдкреНрд░рд╕рд┐рджреНрдз рдореЗрдВ рд╕реЗ рдПрдХ рд╣реИред рдХрд▓реНрдкрдирд╛ рдХрд░реЗрдВ рдХрд┐ рдЖрдкрдХреЛ рдЗрд╕ рдбрд┐рдЬрд╝рд╛рдЗрди рдкреИрдЯрд░реНрди рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ рдПрдХ рдирд┐рд╢реНрдЪрд┐рдд рдСрдмреНрдЬреЗрдХреНрдЯ рдмрдирд╛рдиреЗ рдХреА рдЖрд╡рд╢реНрдпрдХрддрд╛ рд╣реИред
class SimpleBuilder { private constructor() {} static create(): SimpleBuilder { return new SimpleBuilder(); } firstName(firstName: string): this { return this; } lastName(lastName: string): this { return this; } middleName(midleName: string): this { return this; } build(): string { return "what you needs"; } } const builder = SimpleBuilder.create(); // . const result = builder.firstName("F").lastName("L").middleName("M").build();
рдирд┐рдЬреА рдирд┐рд░реНрдорд╛рддрд╛, рдФрд░ рдЖрдорддреМрд░ рдкрд░ ts рдореЗрдВ рдЗрд╕ рдЯреЗрдореНрдкрд▓реЗрдЯ рдХреЗ рдЙрдкрдпреЛрдЧ рдкрд░ рдирд┐рд░рд░реНрдердХ рдирд┐рд░реНрдорд╛рдг рд╡рд┐рдзрд┐ рдХреЛ рди рджреЗрдЦреЗрдВред рдХреЙрд▓ рдЪреЗрди рдкрд░ рдзреНрдпрд╛рди рджреЗрдВред рд╡рд┐рдЪрд╛рд░ рдпрд╣ рд╣реИ рдХрд┐ рддрд░реАрдХреЛрдВ рдХреЛ 1 рдмрд╛рд░ рдХрдбрд╝рд╛рдИ рд╕реЗ рдЙрдкрдпреЛрдЧ рдХрд┐рдпрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдФрд░ рдЖрдкрдХреА рдЖрдИрдбреАрдИ рдХреЛ рднреА рдЗрд╕рдХреА рдЬрд╛рдирдХрд╛рд░реА рд╣реЛрдиреА рдЪрд╛рд╣рд┐рдПред рджреВрд╕рд░реЗ рд╢рдмреНрджреЛрдВ рдореЗрдВ, рдмрд┐рд▓реНрдбрд░ рдЙрджрд╛рд╣рд░рдг рдкрд░ рдХрд┐рд╕реА рднреА рд╡рд┐рдзрд┐ рдХреЛ рдХреЙрд▓ рдХрд░рдиреЗ рдХреЗ рдмрд╛рдж, рдЗрд╕ рд╡рд┐рдзрд┐ рдХреЛ рдЙрдкрд▓рдмреНрдз рд▓реЛрдЧреЛрдВ рдХреА рд╕реВрдЪреА рд╕реЗ рдмрд╛рд╣рд░ рд░рдЦрд╛ рдЬрд╛рдирд╛ рдЪрд╛рд╣рд┐рдПред рдЗрд╕ рддрд░рд╣ рдХреА рдХрд╛рд░реНрдпрдХреНрд╖рдорддрд╛ рдХреЛ рдкреНрд░рд╛рдкреНрдд рдХрд░рдиреЗ рдХреЗ рд▓рд┐рдП, NarrowCallside рдкреНрд░рдХрд╛рд░ рд╣рдорд╛рд░реА рдорджрдж рдХрд░реЗрдЧрд╛ред
type ExcludeMethod<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; type NarrowCallside<T> = { [P in keyof T]: T[P] extends (...args: any) => T ? ReturnType<T[P]> extends T ? (...args: Parameters<T[P]>) => NarrowCallside<ExcludeMethod<T, P>> : T[P] : T[P]; }; class SimpleBuilder { private constructor() {} static create(): NarrowCallside<SimpleBuilder> { return new SimpleBuilder(); } firstName(firstName: string): this { return this; } lastName(lastName: string): this { return this; } middleName(midleName: string): this { return this; } build(): string { return "what you needs"; } } const builder = SimpleBuilder.create(); const result = builder.firstName("F") // ^ - .lastName("L") // ^ - lastName, middleName build .middleName("M") // ^ - middleName build .build(); // ^ - build
рдЦреЛрдЬреЗрдВ : рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдкреНрд░рдХрд╛рд░ рдкреНрд░рдгрд╛рд▓реА рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рдЖрдк рдПрдХ рд╕рдЦреНрдд рдЖрджреЗрд╢ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рдХреЗ рдХреЙрд▓ рдХреЗ рдЕрдиреБрдХреНрд░рдо рдХреЛ рдирд┐рдпрдВрддреНрд░рд┐рдд рдХрд░ рд╕рдХрддреЗ рд╣реИрдВред рдиреАрдЪреЗ рджрд┐рдП рдЧрдП рдЙрджрд╛рд╣рд░рдг рдореЗрдВ, DirectCallside рдкреНрд░рдХрд╛рд░ рдХрд╛ рдЙрдкрдпреЛрдЧ рдХрд░рдХреЗ, рд╣рдо рдЗрд╕реЗ рдкреНрд░рджрд░реНрд╢рд┐рдд рдХрд░рддреЗ рд╣реИрдВред
type FilterKeys<T> = ({[P in keyof T]: T[P] extends (...args: any) => any ? ReturnType<T[P]> extends never ? never : P : never })[keyof T]; type FilterMethods<T> = Pick<T, FilterKeys<T>>; type BaseDirectCallside<T, Direct extends any[]> = FilterMethods<{ [Key in keyof T]: T[Key] extends ((...args: any) => T) ? ((..._: Direct) => any) extends ((_: infer First, ..._1: infer Next) => any) ? First extends Key ? (...args: Parameters<T[Key]>) => BaseDirectCallside<T, Next> : never : never : T[Key] }>; type DirectCallside<T, P extends Array<keyof T>> = BaseDirectCallside<T, P>; class StrongBuilder { private constructor() {} static create(): DirectCallside<StrongBuilder, ["firstName", "lastName", "middleName"]> { return new StrongBuilder() as any; } firstName(firstName: string): this { return this; } lastName(lastName: string): this { return this; } middleName(midleName: string): this { return this; } build(): string { return "what you needs"; } } const sBuilder = StrongBuilder.create(); const sResult = sBuilder.firstName("F") // ^ - firstName build .lastName("L") // ^ - lastName build .middleName("M") // ^ - middleName build .build(); // ^ - build
рдХреБрд▓ рдорд┐рд▓рд╛рдХрд░
рдЖрдЬ рдЯрд╛рдЗрдкрд╕реНрдХреНрд░рд┐рдкреНрдЯ рдкрд░ рдореЗрд░реЗ рд╕рднреА рджрд┐рд▓рдЪрд╕реНрдк рдирд┐рд╖реНрдХрд░реНрд╖ рд╣реИрдВред рдЖрдкрдХрд╛ рдзреНрдпрд╛рди рджреЗрдиреЗ рдХреЗ рд▓рд┐рдП рдЖрдк рд╕рднреА рдХрд╛ рдзрдиреНрдпрд╡рд╛рдж рдФрд░ рдЬрд▓реНрдж рд╣реА рдЖрдкрдХреЛ рджреЗрдЦреВрдВрдЧрд╛ред