TypeScript 常用类型 类型注解 TS是JS的超级,所有JS代码都是合法的TS代码
通过类型注解可以为变量设置类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 let a : string = "hello" ;let b : number = 123 ;let c : boolean = false ;function greet (name : string , times : number ): string { const str = `你好${name} ` ; for (let i = 0 ; i < times; i++) { console .log (str); } return str; } greet ("孙悟空" , 5 );
类型推断 当我们没有明确指定一个变量的类型时,TS会自动对变量的类型进行推断,所以,通常情况下我们不需要为变量设置类型注解,都交给TS自动推断
1 2 3 4 let a : string = "hello" ; let b; b = 123 ; b = "hello" ;
原始值
number
string
boolean
bigint 大整数
symbol 符号
undefined
null
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 let a : number = 10 ;a = 0x123 ; a = 0b1111 ; a = 0o1234 ; a = NaN ; a = Infinity ; let b : string = "hello" ;b = `hello` let c : boolean = true ;c = false ; let d : bigint = 100n ;let e : symbol = Symbol ();
数组
Array
T[] (推荐使用)
1 2 3 4 5 let a : Array <number >;a = [1 , 2 , 3 , 4 , 5 ]; let b : string [];b = ["a" , "b" , "c" ];
any
表示任意值
当我们为一个变量设置any后,它可以接受任何值
同时它也可以赋值给任意类型的变量
当我们为一个变量设置any类型后,那么它将跳过所有的TS的检查,可以对它调用任意属性或方法,这将导致出现运行时异常的概率大大增加
基于以上特点,在开发时尽量不要使用它
1 2 3 4 5 6 7 8 let a : any ;a = 123 ; a = "hello" ; a = [1 , 2 , 3 , 4 ]; let b : boolean = a;let c;
unknow 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 let a : unknown ;a = 123 ; a = "hello" ; a = [1 , 2 , 3 ]; console .log ((<number[]>a).length); // 断言 console.log((a as number[]).length); // 断言 a = "hello"; if (typeof a === "string") { a.toUpperCase(); } let b: unknown = a; let c: any = a;
对象类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 let obj : object = { name : "孙悟空" }if ("name" in obj) { console .log (obj.name ); } let obj2 : { name : string ; age ?: number } = { name : "孙悟空" , age : 18 }console .log (obj2.name , obj2.age );class Person { name : string ; age : number ; constructor (name : string , age : number ) { this .name = name; this .age = age; } } let p1 : Person = { name : "孙悟空" , age : 18 }let p2 : Person = { name : "猪八戒" , age : 28 }interface Dog { name : string ; age : number ; } let d1 : Dog = { name : "旺财" , age : 5 }
联合类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 let a : string | number | boolean ;a = "hello" ; a = 123 ; a = true ; interface Person { name : string ; age : number ; } interface Dog { age : number ; } let someOne : Person | Dog = { name : "孙悟空" , age : 18 }someOne = { age : 22 } function fn (personOrDog : Person | Dog ) { personOrDog.age ; (personOrDog as Person ).name ; if ("name" in personOrDog) { personOrDog.name ; } }
交叉类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 interface Named { name : string ; } interface Aged { age : number ; } let a : Named & Aged = { name : "孙悟空" , age : 18 }
类型别名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 type str = string ;type bool = boolean ;type strOrNumOrBool = string | number | boolean ;let a : strOrNumOrBool;interface Named { name : string ; } interface Aged { age : number ; } type Person = Named & Aged ;
接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 interface Person { readonly name : string ; age ?: number ; sayHello?(): void ; } const p : Person = { name : "孙悟空" , age : 18 , sayHello : () => { } }interface Animal { name : string ; age : number ; } interface Snake extends Animal {} class Dog implements Animal { name : string ; age : number ; constructor (name : string , age : number ) { this .name = name; this .age = age; } bark ( ) { console .log ("汪汪汪" ); } } class Cat implements Animal { name : string ; age : number ; constructor (name : string , age : number ) { this .name = name; this .age = age; } miao ( ) { console .log ("喵喵喵" ); } } function fn (animal : Animal ) { if (animal instanceof Dog ) { animal.bark (); } else if (animal instanceof Cat ) { animal.miao (); } } fn (new Dog ("旺财" , 5 ));fn (new Cat ("喵喵" , 5 ));
类型断言 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 let str : unknown = "Hello World" ;(<string >str).length ; (str as string ).length ;
字面量类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 type Direction = "left" | "right" | "up" | "down" ;type DiceValue = 1 | 2 | 3 | 4 | 5 | 6 ;let dir : Direction = "right" ;let dice : DiceValue = 1 let a = "hello" ; const b = "hello" ; let c = { x : 1 , y : 2 } const d = { x : 1 , y : 2 }let e = "haha" as const ; let f = { x : 1 , y : 2 } as const
空类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function fn ( ): void { return undefined ; }
never 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 function fn ( ): never { throw new Error ("出错了" ); } type Direction = "left" | "right" ;function fn3 (dir : Direction ) { switch (dir) { case "left" : console .log ("向左" ); break ; case "right" : console .log ("向右" ); break ; default : const unreachabe : never = dir; break ; } }
非空断言 1 2 3 4 5 6 7 8 9 10 11 function fn (str : string | null ) { if (typeof str === "string" ) { str.length ; } (str as string ).length ; let num = str!.length ; let num2 = str?.length ; }
控制流分析 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function doSomething (value : string | number ) { if (typeof value === "string" ) { value.toUpperCase (); } else { value += 10 ; } }
typeof 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function doSomething (value : string | number ) { if (typeof value === "string" ) { value.toUpperCase (); } else { value += 10 ; } }
相等性收窄 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 function fn (str : string | undefined ) { if (str !== undefined ) { console .log (str.length ); } } interface Circle { kind : "circle" ; radius : number ; } interface Square { kind : "square" ; sideLength : number ; } type Shape = Circle | Square ;function getArea (shape : Shape ): number { if (shape.kind === "circle" ) { return Math .PI * shape.radius ** 2 ; } return shape.sideLength ** 2 ; }
in运算符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 interface Circle { radius : number ; } interface Square { sideLength : number ; } type Shape = Circle | Square ;function getArea (shape : Shape ): number { if ("radius" in shape) { return Math .PI * shape.radius ** 2 ; } return shape.sideLength ** 2 ; }
instanceof 1 2 3 4 5 6 7 8 9 10 11 12 13 function fn (value : string [] | Date ) { if (value instanceof Date ) { value } else { value } }
赋值收窄 1 2 3 4 5 6 7 8 9 10 11 12 let x : string | number | boolean ;x = 10 ; x = "hello" ; x = true ;
类型谓词 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 interface Circle { kind : "circle" ; radius : number ; } interface Square { kind : "square" ; sideLength : number ; } type Shape = Circle | Square ;function isCircle (shape : Shape ): shape is Circle { return shape.kind === "circle" ; } function getArea (shape : Shape ): number { if (isCircle (shape)) { return Math .PI * shape.radius ** 2 ; } return shape.sideLength ** 2 ; }
断言函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 interface Circle { kind : "circle" ; radius : number ; } function isCircle (value : any ): asserts value is Circle { if (value.kind !== "circle" ) { throw new Error ("value的类型不是Circle" ); } } let a : unknown = {}isCircle (a); interface Data { msg : string ; } function isData (data : any ): asserts data is Data { if (data.msg === undefined ) throw new Error ("Data的结构有误!" ); } function getData ( ): Promise <Data > { return new Promise ((resolve, reject ) => { const data = { msg : "这是合法数据!" } isData (data); resolve (data); }) } getData () .then (data => console .log (data)) .catch (err => console .log ("出错了" ));
函数 函数 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 let fn : Function ;fn = function ( ) { } fn = (a : string ) => 123 ; let fn2 : (str : string ) => string ;fn2 = (str : string ) => "hello" ; type MyFunction = (str : string ) => string ;type MyFun2 = { (a : number , b : number ): number ; } interface MyFun3 { (a : string , b : string ): string } let sum : MyFun2 = function (a : number , b : number ) { return a + b; } let getStr : MyFun3 = (a : string , b : string ) => a + b;
函数的类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 type MyFunction = (str : string ) => string ;let fn : MyFunction = (str : string ) => "hello" ;type MyFunction2 = (str : string ) => string ;let fn2 : MyFunction2 = (str : string | number ) => "hello" ;interface MyObj { test (str : string | number ): void ; } let obj : MyObj = { test (a : string ) { } } type MyFunction3 = () => void ;
构造签名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 interface MyFn { new (str : string ): any ; } let Fn : MyFn = class { a : string ; constructor (a : string ) { this .a = a; } } new Fn ("hello" );
使用的场景 1 2 3 4 5 6 7 8 9 type MyFunction = (str : string ) => void ;let fn : MyFunction = (a ) => "hello" ;function eventHandler (event : string , callback : MyFunction ) { }eventHandler ("hello" , (a : string ) => { });
可选参数 1 2 3 4 5 6 7 8 9 10 11 12 type MyFn = (num : number , str ?: string ) => void let fn : MyFn = (a, b ) => { if (typeof b === "string" ) console .log (b.length ); }
剩余参数 1 2 3 4 5 6 type MyFn = (a : string , b ?: number , ...args : any [] ) => void ;
泛型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 function firstElement<T>(arr : T[]): T { return arr[0 ]; } let r1 = firstElement<string >(["hello" , "haha" , "xixi" ]);let r2 = firstElement<number >([1 , 2 , 3 , 4 ]);function fn<T>(arg : T): T { return arg; } interface MyInterface <T> { get (): T; } let inter : MyInterface <string > = { get ( ) { return "hello" ; } } class MyClass <T>{ property : T; constructor (property : T ) { this .property = property; } } type MyType <T> = T;
泛型的约束 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 function getLength<T extends { length : number }>(a : T): number { return a.length ; } getLength ("hello" );getLength ([1 , 2 , 3 , 4 ]);function getProperty<T, K extends keyof T>(obj : T, propName : K) { return obj[propName]; } getProperty ({ name : "孙悟空" , age : 18 }, "age" );getProperty ({ name : "孙悟空" , age : 18 }, "name" );interface Person { name : string ; age : number ; gender : string ; } type objKeys = keyof Person ;
重载 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 function sum (a : string , b : string ): string ;function sum (a : number , b : number ): number ;function sum (a : string | number , b : string | number ): string | number { if (typeof a === "string" && typeof b === "string" ) { return a + b; } else if (typeof a === "number" && typeof b === "number" ) { return a + b; } throw new Error ("Type Error" ); } let result = sum (123 , 123 );function fn (a : string ): void ;function fn (a : boolean , b : number ): void ;function fn ( ) { }function fn2 (a : string ): void ;function fn2 (a : boolean , b : number ): void ;function fn2 (a : string | boolean , b ?: number ) { }function len (str : string ): number ;function len (arr : any [] ): number ;function len (value : string | any [] ): number { return value.length ; } len ("hello" );len ([1 , 2 , 3 , 4 ]);function len2 (val : string | any [] ): number { return val.length ; } len2 ("hello" );len2 ([1 , 2 , 3 , 4 ]);len2 (Math .random () > 0.5 ? "hello" : [1 , 2 , 3 , 4 ]);
this 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 function fn (this : any ) { console .log (this ); } class Person { name : string ; age : number ; constructor (name : string , age : number ) { this .name = name; this .age = age; } sayHello (this : Person ) { console .log (this .name ); } test = () => { console .log (this .name ); } } function filterPerson (filter : (this : Person) => boolean ) { }filterPerson (function ( ) { this .name ; return true ; });
对象 可选和只读 1 2 3 4 5 6 7 8 9 10 11 12 13 interface Person { readonly name : string ; age ?: number ; } const p : Person = { name : "孙悟空" , age : 18 }const obj : { name : string ; age ?: number } = p;obj.name = "猪八戒" ; console .log (p.name );
索引签名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 interface Inter { [propName : string ]: string | number ; } interface Inter2 { [index : number ]: number ; } const obj : Inter = { name : "孙悟空" , gender : "男" , age : 18 , 0 : 123 }const obj2 : Inter2 = [123 , 456 ];interface Inter { [key : symbol ]: string ; } let s = Symbol ();let obj : Inter = { [s]: "hello" }console .log (obj[s]);interface Inter2 { [key : string ]: any ; name : string ; gender : string ; age : number ; } interface Inter3 { [propsName : string ]: string | number ; [index : number ]: number } let obj2 : Inter2 = { name : "孙悟空" , gender : "男" , age : 18 }let obj3 : Inter3 = { name : "孙悟空" , 0 : 123 , 1 : 456 }
接口继承和交叉类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 interface A { name : string ; } interface B { age : number ; } interface C extends A, B { address : string ; gender : string ; } class D implements A, B { name : string = "孙悟空" ; age : number = 18 ; } type E = A & B;let e : E = { name : "孙悟空" , age : 18 }interface F { name : string ; gender : string } interface G { age : number ; gender : boolean ; } type H = F & G;
只读数组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const arr : ReadonlyArray <number > = [1 , 2 , 3 , 4 , 5 ];const arr2 : readonly number [] = [1 , 2 , 3 , 4 , 5 ];const map : ReadonlyMap <string , number > = new Map ([["one" , 1 ], ["two" , 2 ]]);const set : ReadonlySet <string > = new Set (["孙悟空" , "猪八戒" , "沙和尚" ]);
元组 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 let tuple : [string , number ] = ["hello" , 123 ];function fn (person : [string , number , string ] ) { }function fn2 ( ) { return [() => { }, true , false , null ]; } function fn3 (a : string , b : number , ...args : [string , number , boolean ] ) { };fn3 ("hello" , 123 , "aaa" , 456 , true );let tuple2 : readonly [string , number ] = ["hello" , 123 ];let tuple3 : [string , number ?] = ["hello" , 123 ];let tuple4 : [string , number , ...boolean []] = ["aaa" , 123 , true , false ];let tuple5 : [string , ...boolean [], number ] = ["aaa" , true , false , 123 ];let tuple6 : [...boolean [], string , number ] = [true , false , "aaa" , 123 ];
获取类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 interface Person { name : string , age : number , gender : string } type PersonProerties = keyof Person ; let a = "hello" ;let b : typeof a = "哈哈哈" ;let obj = { name : "孙悟空" , age : 18 } type GetType = typeof obj;type PropertyType = Person ["name" ]; type PropertyType2 = typeof obj.name ;
条件类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 type isString<T> = T extends string ? "yes" : "no" ;let b : isString<number > = "no" ;type NumberArr = string [];type ElementType <T> = T extends Array <infer U> ? U : T;let c : ElementType <NumberArr >;let d : ElementType <boolean >;
映射类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 interface Person { name : string ; age : number ; address : string ; } type MyPerson = { [P in keyof Person ]: Person [P]; } type ReadonlyPerson <T> = { readonly [P in keyof T]: T[P]; } let p : Readonly <Person > = { name : "孙悟空" , age : 18 , address : "花果山" }type Partial <T> = { [P in keyof T]?: T[P]; } interface Animal { name ?: string ; age : number ; } type MyAnimal = { [P in keyof Animal ]-?: Animal [P]; }
工具类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 interface Todo { title ?: string ; description ?: string ; } let todo : Required <Todo > = { title : "hello" , description : "哈哈哈哈" }function printObj<T>(obj : Required <T>) { console .log (obj); } printObj<Todo >({ title : "hello" , description : "哈哈哈哈" }); interface Person { name : string ; age : number ; gender : string ; address : string ; } let p1 : Pick <Person , "name" | "age" > = { name : "孙悟空" , age : 18 }let p2 : Omit <Person , "name" | "age" > = { gender : "男" , address : "花果山" }type MyType = Record <"name" | "gender" | "address" , string >;let personRecord : Record <string , Person > = { tom : { name : "tom" , age : 18 , gender : "男" , address : "花果山" }, tom2 : { name : "tom2" , age : 18 , gender : "男" , address : "花果山" } } type M1 = Exclude <"a" | "b" | "c" , "b" >; type M2 = Exclude <"a" | "b" | "c" , "a" | "b" >; type M3 = Extract <"a" | "b" | "c" , "a" >; type M4 = Extract <"a" | "b" | "c" , "a" | "c" >; type T1 = NonNullable <string | null | undefined | number >;const removeNullFromArray1 = <T>(array : T[]): T[] => { return array.filter (item => item !== null && item !== undefined ); } let result1 = removeNullFromArray1 ([1 , 2 , 3 , null , undefined , 123 ]); function removeNullFromArray2<T>(array : T[]): NonNullable <T>[] { return array.filter (item => item !== null && item !== undefined ) as NonNullable <T>[]; } let result2 = removeNullFromArray2 ([1 , 2 , 3 , null , undefined , 123 ]);
1 2 3 4 5 6 7 8 9 10 11 interface Person { name : string ; age : number ; gender : string ; address : string ; } let personRecord : Record <string , Person > = { tom : { name : "tom" , age : 18 , gender : "男" , address : "花果山" }, [s]: { name : "tom2" , age : 18 , gender : "男" , address : "花果山" } };
TypeScript 对这个赋值操作的理解是:
tom 属性 :'tom' 是一个字符串,符合 [key: string] 的索引签名规则。所以 tom 属性的检查通过了。
[s] 属性 :s 是一个 Symbol。虽然 Record<string, Person> 的索引签名只定义了 string 类型的键,但 TypeScript 认为,在对象创建时 就明确写出的属性,是一种“显式声明”,而不是通过动态字符串访问。它允许这种显式声明的 Symbol 键与 string 索引签名并存。
可以理解为,索引签名主要用于控制后续 的、动态 的属性访问,比如:
1 2 3 4 personRecord["some_other_key" ] = { ... }; personRecord[Symbol ("another_id" )] = { ... };
当试图在对象创建之后通过一个 Symbol 去给 personRecord 赋值时,TypeScript 就会严格按照 Record<string, Person> 的 string 索引签名进行检查,并告诉你没有为 symbol 类型定义索引,从而报错
编译时不报错 :因为在对象字面量初始化 时,TypeScript 允许你定义 JavaScript 中所有合法的键类型(string, number, symbol),即使类型定义中的索引签名只指定了 string。它将 [s] 视为一个“已知”的、显式定义的属性,而不是一个需要匹配 [key: string] 模式的动态属性。
使用时会报错 :当你试图在对象创建后,通过一个 symbol 变量去动态访问或赋值 时,TypeScript 就会严格执行索引签名的规则,此时就会报错。
字符串工具类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 type MyType = "hello" ;let a : Uppercase <MyType > = "HELLO" ;let b : Lowercase <"HELLO" > = "hello" ;let c : Capitalize <MyType > = "Hello" ;let d : Uncapitalize <"HELLO" > = "hELLO" ;
映射类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 interface Person { name : string ; age : number ; } type NewPerson = { [P in keyof Person as `my${Capitalize<P>} ` ]: Person [P]; } interface Person2 { name : string ; age : number ; 1 : number ; } type NewPerson2 = { [P in keyof Person2 as `${string & P} ` ]: Person2 [P]; } type NewPerson3 = { [P in keyof Person2 as `${Exclude<P, 1 >} ` ]: Person2 [P]; } type NewPerson4 = { [P in keyof Person2 as `${Extract<P, "name" | "age" >} ` ]: Person2 [P]; } type NewPerson5 = { [P in keyof Person2 as `get${Capitalize<string & P>} ` ]: Person2 [P]; } type NewPerson6 = { [P in keyof Person2 as P extends string ? `get${Capitalize<P>} ` : never ]: Person2 [P]; }
模板字符串类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 type Fruit = "apple" | "orange" | "banana" ;type Hello = `Hello ${Fruit} ` ;function eventHandler<T, K extends string & keyof T>( obj : T, eventName : `${K} Changed` , callback : (newValue : T[K] ) => void ) { } eventHandler ( { name : "孙悟空" , age : 18 , gender : "男" }, "ageChanged" , (newValue ) => { } )
类 类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 class Person { name : string ; age : number ; gender!: string ; constructor (name : string , age : number ) { this .name = name; this .age = 10 ; } seyHello ( ) { console .log (`大家好!${this .name} 在这里祝大家快乐` ); } test = () => { console .log ("测试方法" , this .name ); } } const p1 = new Person ("孙悟空" , 18 );console .log (p1);
构造函数 1 2 3 4 5 6 class MyClass { constructor (x : number , y : string ); constructor (x : boolean ); constructor (x : number | boolean , y ?: string ) { } }
属性访问器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Person { #name : string ; #age : number ; constructor (name : string , age : number ) { this .#name = name; this .#age = age; } get name () { console .log ("get执行了" ); return this .#name; } set name (name : string ) { console .log ("set执行了" ); this .#name = name; } } let p = new Person ("孙悟空" , 18 );p.name ; p.name = "猪八戒" ;
继承 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 class A { name : string ; constructor ( ) { console .log ("父类A的构造函数执行了!!" ); this .name = "孙悟空" ; } method ( ) { console .log ("method" ); } } class B extends A { constructor ( ) { super (); } newMethod ( ) { super .method (); console .log ("b添加的方法" ); } } const b : A = new B ();b.method (); function fn1 (arg : A ) { }fn1 (b);class Animal { name = "动物" ; } class Dog extends Animal { }class Cat extends Animal { }function fn2 (arg : Animal ) { }fn2 (new Dog ());
成员修饰符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 class Myclass { public name = "孙悟空" ; protected age = 18 ; private gender = "男" ; protected sayHello ( ) { this .name = "xxx" ; } } class A extends Myclass { test ( ) { this .age ; } } const mc = new Myclass ();
静态修饰符 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 class Myclass { age = "123" ; static #staticProp = "静态属性" ; static staticMethod ( ) { console .log (this .#staticProp); } static { this .#staticProp = "我修改一下" ; } } class Person <T>{ name : T; constructor (name : T ) { this .name = name; } }
实现接口 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 interface Inter { name : string ; age : number ; gender : string ; } interface A { }class B { }class Person extends B implements Inter , A { name = "孙悟空" ; age = 18 ; gender = "男" ; address = "花果山" ; } function printInfo (obj : Inter ) { console .log (obj.name , obj.age , obj.gender ); } printInfo (new Person ());
抽象类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 abstract class MyAbClass { abstract name : string ; abstract sayHello (): void ; } class A extends MyAbClass { constructor (public name : string ) { super (); } sayHello (): void { } }
其他 命名空间 1 2 3 4 5 6 7 8 9 10 11 12 13 namespace MyModule { let a = 10 ; export let b = "hello" ; export function fn ( ) { } } MyModule .b ;MyModule .fn ;
枚举 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 let status = 1 ;enum Status { Pending , Approved , Rejected } if (status === Status .Pending ) { console .log ("加载中" ); } else if (status === Status .Approved ) { console .log ("加载完毕。。" ); } else if (status === Status .Rejected ) { console .log ("加载失败。。" ); } let a = Status .Approved ;let b = Status [2 ];console .log (a, b); enum Color { Red = "red" , Green = "green" , Blue = "blue" } function setColor (color : Color ) { }setColor (Color .Red );const enum Num { One , Two , Three }
声明 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 declare let myGlobal : number ; declare function printLog (msg : string ): void ;declare class JQueryIntance { text (): string ; } declare function jQuery (selector : string ): JQueryIntance ;declare var $ : typeof jQuery;$("#box1" ).text ();
声明文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 import Person , { abc } from "../../types/scope" ;export { }abc.startsWith ("a" ); const p : Person = {}
scope.d.ts
1 2 3 export let abc : string ;export default interface Person { }
装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 function render (target : Function ) { const oldRender = target.prototype .render ; target.prototype .render = function ( ) { return `<h1>${oldRender.apply(this )} </h1>` ; } } @render class Person { constructor (public name : string ) { } render ( ) { return this .name ; } } @render class News { constructor (public title : string ) { } render ( ) { return this .title ; } } const p = new Person ("孙悟空" );const n = new News ("孙悟空大闹天宫" );console .log (p.render ());console .log (n.render ());
类装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 function render (target : Function ) { const oldRender = target.prototype .render ; target.prototype .render = function ( ) { return `<h1>${oldRender.apply(this )} </h1>` ; } } function deco (target : Function ) { target.prototype .age = 18 ; } function deco2<T extends { new (...args : any []): any }>(target : T) { return class extends target { } } @deco class Person { constructor (public name : string ) { } render ( ) { return this .name ; } } function Component1 (target : Function ) { target.prototype .selector = "my-news" ; target.prototype .template = "<h1>今天天气真不错!</h1>" ; } function Component2 (options : { selector: string ; template: string } ) { return function (target : Function ) { target.prototype .selector = options.selector ; target.prototype .template = options.template ; } } @Component2 ({ selector : "news" , template : "<h1>今天天气真不错!</h1>" }) class News { constructor (public title : string ) { } }
属性装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 function deco (target : object , propertyName : string ) { console .log (target, propertyName); } class Person { @deco name = "孙悟空" ; age = 18 ; }
元数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 import "reflect-metadata" ;export { }class User { username : string ; password : string ; nickname : string ; constructor (username : string , password : string , nickname : string ) { this .username = username; this .password = password; this .nickname = nickname; } } const u = new User ("孙悟空" , "123123" , "大师兄" );const reqKey = Symbol ();Reflect .defineMetadata (reqKey, true , User .prototype , "username" );const result = Reflect .getMetadata (reqKey, u, "password" );console .log (result);function checkRequired (user : User ) { for (const prop in user) { if (prop === "username" || prop === "password" ) { if (!user[prop]) { console .log (`${prop} 属性是必须的` ); } } } }
属性装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import "reflect-metadata" ;export { }const reqKey = Symbol ();function required (target : any , propName : string ) { Reflect .defineMetadata (reqKey, true , target, propName); } class User { @Reflect .metadata (reqKey, true ) username : string ; @required password : string ; nickname : string ; constructor (username : string , password : string , nickname : string ) { this .username = username; this .password = password; this .nickname = nickname; } } const u = new User ("" , "" , "" );function checkRequired (obj : { [key: string ]: any } ) { for (const prop in obj) { if (Reflect .getMetadata (reqKey, obj, prop)) { if (!obj[prop]) { console .log (`${prop} 是必须的` ); } } } } checkRequired (u);
方法装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 function deco (target : any , methodName : string , descriptor : PropertyDescriptor ) { descriptor.value = () => { console .log ("新函数" ); } } function logger (target : any , methodName : string , descriptor : PropertyDescriptor ) { const oldMethod : Function = descriptor.value ; descriptor.value = function (...args : any [] ) { console .log (`${methodName} 函数调用了 - ${new Date ()} ` ); oldMethod.apply (this , args) } } class Person { @deco sayHello ( ) { console .log ("sayHello()方法" ); } @logger sum (a : number , b : number ) { return a + b; } } const p = new Person ();p.sum (123 , 345 );
访问器装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 function setterLog (target : any , propName : string , descriptor : PropertyDescriptor ) { const oldSet = descriptor.set ; descriptor.set = function (arg : any ) { console .log (`${propName} 被修改了,在${new Date ()} ` ); oldSet?.call (this , arg); } } class Person { private _name : string ; constructor (name : string ) { this ._name = name; } @setterLog get name () { return this ._name ; } set name (name : string ) { this ._name = name; } } const p = new Person ("孙悟空" );p.name = "猪八戒" ; console .log (p.name );
参数装饰器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 function deco (target : any , methodName : string , parameterIndex : number ) { console .log (target, methodName, parameterIndex); } class Person { sun (@deco a : number , b : number ) { return a + b; } }
装饰器执行顺序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 function deco (name : string ) { console .log ("工厂调用了" , name); return function (...args : any [] ) { } } @deco ("类装饰器" )class Person { @deco ("实例属性" ) name = "孙悟空" ; @deco ("静态属性" ) static age = 18 ; @deco ("实例方法" ) sum (a : number , @deco ("实例参数" ) b : number ) { return a + b; } @deco ("静态方法" ) static sayHello (@deco ("静态参数" ) a : string ) { console .log (`Hello ${a} ` ); } } function f (name : string ) { return function (target : any , methodName : string , desc : PropertyDescriptor ) { const oldMethod = desc.value desc.value = function ( ) { console .log (`${name} 开始...` ); oldMethod (); console .log (`${name} 结束...` ); } } } class Dog { @f ("1" ) @f ("2" ) @f ("3" ) test ( ) { console .log ("test方法..." ); } } new Dog ().test ();