classGreeter{ readonly name:string="world"; constructor(otherName?:stirng){ if(otherName!==undefined){ this.name=otherName; } } err(){ this.name="not ok"; // Cannot assign to 'name' because it is a read-only property. } }
classMyClass{ name = "MyClass"; getName = () => { returnthis.name; }; } const c = new MyClass(); const g = c.getName; // Prints "MyClass" instead of crashing console.log(g());
转为a.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
var MyClass = /** @class */ (function () { functionMyClass() { var _this = this; this.name = "MyClass"; this.getName = function () { return _this.name; }; } return MyClass; }()); var c = new MyClass(); c.getName(); var g = c.getName; console.log(g());
classClearableBoxextendsBox{ clear() { this.contents = ""; } } const a = new ClearableBox(); const b = a.set("hello");
// const b: ClearableBox
下面这个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
classBox{ content: string = ""; sameAs(other: this) { return other.content === this.content; } } classDerivedBoxextendsBox{ otherContent: string = "?"; } const base = new Box(); const derived = new DerivedBox(); derived.sameAs(base); // Argument of type 'Box' is not assignable to parameter of type 'DerivedBox'. // Property 'otherContent' is missing in type 'Box' but required in type 'DerivedBox'.
type Arrayish={[n:number]:unknown}; type A=keypf Arrayish; //type A=number type Mapish={[k:string]:boolean}; type M=keyof Mapish; //type M=string |number
type NameOrId<T extendsnumber|string>=T extendsnumber?IdLabel:NameLabel; functioncreateLabel<Textendsnumber|string>(idOrName:T):NameOrId<T>{ throw"unimplemented"; } let a=createLabel("typescript"); //let a:NameLabel let b=createLabel(2.8); //let b:IdLabel let c=createLabel(Math.radom()?"hello":42); //let c:NameLabel|IdLabel
条件类型约束
1 2 3 4 5 6 7 8 9 10 11
type MessageOf<T extends {message:unknown} ? T["message"]:never; interface Email { message:string; } interface Dog { bark():void; } type EmailMessageContents=MessageOf<Email>; //type EmailMessageContents=string type DogMessageContents=MessageOf<Dog>; //type DogMessageContents=nerver
在条件类型里推断
infer关键词,可以从正在比较的类型中推断类型,然后在true分支里引用该推断结果
1 2 3 4 5 6 7
type Flatten<T>=T extendsany[]?T[number]:T;//number索引用来获取数组元素的类型 type Str=Flatten<string[]>; //type Str=string type Num=Flatten<number>; //type Num=number; //用infer type Flatten<Type>=Type extendsArray<infer Item>?Item:Type
使用infer写一些有用的类型帮助别名,我们可以获取一个函数返回的类型:
1 2 3 4 5
type GetReturnType<Type>=Type extends (...args:nerver[])=>infer Return ?Return :never; type Num=GetReturnType<()=>number>; //type Num=number; type Str=GetReturnType<(x:string)=>string>; //type Str=string
functionf(){ return {x:10,y:3}; } type P=ReturnType<f>;// 'f' refers to a value, but is being used as a type here. Did you mean 'typeof f'? type P=ReturnType<typeof f> // type P = { // x: number; // y: number; // }
functiongetProperty<Type,KeyextendskeyofType>(obj:Type,key:Key){ return obj[key]; } let x={a:1,b:2,c:3,d:4}; getProperty(x,'a'); getProperty(x,'m'); // Argument of type '"m"' is not assignable to parameter of type '"a" | "b" | "c" | "d"'.
interface Animal { name:string } interface Dog extends Animal { breed:string; } interface NotOkay { [x:number]:Animal; [x:string]:Dog; //error TS2413: 'number' index type 'Animal' is not assignable to 'string' index type 'Dog'. }
functiondraw(circle:Colorful&Circle){ console.log(`Color was ${circle.color}`); console.log(`Radius was ${circle.radius}`); } // okay draw({ color: "blue", radius: 42 }); // oops draw({ color: "red", raidus: 42 }); // Argument of type '{ color: string; raidus: number; }' is not assignable to parameter of type 'Colorful & Circle'. // Object literal may only specify known properties, but 'raidus' does not exist in type 'Colorful & Circle'. Did you mean to write 'radius'?
接口继承和交叉类型
区别在于冲突怎么处理,这也是选择要使用哪种方式的主要原因
1 2 3 4 5 6 7 8 9
interface Colorful { color:string; } interface ColorfulSub extends Colorful { color:number; } // Interface 'ColorfulSub' incorrectly extends interface 'Colorful'. // Types of property 'color' are incompatible. // Type 'number' is not assignable to type 'string'.
使用继承方式,如果重写类型会导致编译错误,但交叉类型不会
1 2 3 4 5 6
interface Colorful { color:string; } type ColorfulSub=Colorful&{ color:number }
不报错,color属性的类型是nerver,取得的是string和number的交集
类型别名和接口:
类型别名不同于接口,可以描述的不止是对象类型,我们也可以用类型别名写一些其他种类的泛型帮助类型
1 2 3 4 5 6 7 8 9 10 11
type OrNull<Type> = Type | null; type OneOrMany<Type> = Type | Type[]; type OneOrManyOrNull<Type> = OrNull<OneOrMany<Type>>; type OneOrManyOrNull<Type> = OneOrMany<Type> | null type OneOrManyOrNullStrings = OneOrManyOrNull<string>; type OneOrManyOrNullStrings = OneOrMany<string> | null
元组类型在重度依赖约定的 API 中很有用,因为它会让每个元素的意义都很明显。当我们解构的时候,元组给了我们命名变量的自由度。
元组类型中,可以写一个可选属性,但可选元素必须在最后面,而且会影响类型的length
1 2 3 4 5 6 7 8
type Either2dOr3d=[number,number,number?]; functionsetCoordinate(coord:Either2dOr3d){ const [x,y,z]=coord; //const z:number|undefined console.log(`Provided coordinates had ${coord.length} dismensions`); //(property) length:2|3 }
Tuples可以使用剩余元素语法,但必须是array/tuple类型:
1 2 3
type StringNumberBooleans=[string,number,...boolean[]]; type StringBooleansNumber = [string, ...boolean[], number]; type BooleansStringNumber = [...boolean[], string, number];
let point=[3,4] asconst; functiondistanceFromOrigin([x,y]:[number,number]){ returnMath.sqrt(x**2+y**2); } distanceFromOrigin(point); // Argument of type 'readonly [3, 4]' is not assignable to parameter of type '[number, number]'. // The type 'readonly [3, 4]' is 'readonly' and cannot be assigned to the mutable type '[number, number]'.
interface DB { filterUsers(filter: (this: User) =>boolean): User[]; } const db = getDB(); const admins = db.filterUsers(() =>this.admin); // The containing arrow function captures the global value of 'this'. // Element implicitly has an 'any' type because type 'typeof globalThis' has no index signature.
Function.prototype.bind=function(context){ if(typeofthis !=='function'){ thrownewError("Function .prototype.bind-what is trying to be bound is not callable") } var self=this; var args=Array.prototype.slice.call(arguments,1); var fNOP=function(){}; var fBound=function(){ var bindArgs=Array.prototype.slice.call(arguments); return self.apply(thisinstanceof fNOP?this:context,args.concat(bindArgs)); } fNOP.prototype=this.prototype; fBound.prototype=new fNOP(); return fBound;