高级类型 交叉类型 注:交叉类型是将多个类型合并为一个类型。
1 2 3 4 5 6 7 8 9 10 11 12 function extend <T , U >(first: T, second: U ): T & U { let result = <T & U>{}; for (let id in first) { (<any >result)[id] = (<any >first)[id]; } for (let id in second) { if (!result.hasOwnProperty(id)) { (<any >result)[id] = (<any >second)[id]; } } return result; }
联合类型 注:联合类型是不确定的多个类型中的一个。
1 function padLeft (value: string , padding: string | number ) {}
类型别名 注:类型别名会给一个类型起个新名字,不会新建一个类型。
1 2 3 4 5 6 type Container<T> = { value: T };type Tree<T> = { value: T; left: Tree<T>; right: Tree<T>; };
索引类型 注:使用索引类型,编译器能够检查使用了动态属性名的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13 function pluck <T , K extends keyof T >(o: T, names: K[] ): T [K ][] { return names.map(n => o[n]); } interface Person { name: string ; age: number ; } let person: Person = { name: "Jarid" , age: 35 }; let strings: string [] = pluck(person, ["name" ]);
映射类型 注:新类型以相同的形式去转换旧类型里每个属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 interface PersonPartial { name?: string ; age?: number ; } interface PersonReadonly { readonly name: string ; readonly age: number ; } type Readonly<T> = { readonly [P in keyof T]: T[P]; }; type Partial<T> = { [P in keyof T]?: T[P]; };
命名空间 不同文件的命名空间 注:避免同名冲突,隐藏实现细节。
A 文件:
1 2 3 4 5 namespace Validation { export interface StringValidator { isAcceptable(s: string ): boolean ; } }
B 文件:
1 2 3 4 5 6 7 8 namespace Validation { const lettersRegexp = /^[A-Za-z]+$/ ; export class LettersOnlyValidator implements StringValidator { isAcceptable(s: string ) { return lettersRegexp.test(s); } } }
别名 注:简化命名空间。
1 2 3 4 5 6 7 8 9 namespace Shapes { export namespace Polygons { export class Triangle {} export class Square {} } } import polygons = Shapes.Polygons;let sq = new polygons.Square();
外部命名空间 注:引入外部 JS 库,使用外部命名空间声明,declare 关键字代表声明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 declare namespace D3 { export interface Selectors { select: { (selector: string ): Selection; (element: EventTarget): Selection; }; } export interface Event { x: number ; y: number ; } export interface Base extends Selectors { event: Event; } } declare var d3: D3.Base;
装饰器 前置:tsconfig.json 中启用 experimentalDecorators。 注:装饰器使用 @expression 这种形式,expression 求值后必须为一个函数,它会在运行时被调用,被装饰的声明信息做为参数传入。
装饰器工厂 注: 装饰器工厂就是一个简单的函数,它返回一个表达式,以供装饰器在运行时调用。
1 2 3 4 5 6 7 function color (value: string ) { return function (target ) { }; }
装饰器组合 注:装饰器工厂就是一个简单的函数,它返回一个表达式,以供装饰器在运行时调用。
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 function f ( ) { console .log("f(): evaluated" ); return function ( target, propertyKey: string , descriptor: PropertyDescriptor ) { console .log("f(): called" ); }; } function g ( ) { console .log("g(): evaluated" ); return function ( target, propertyKey: string , descriptor: PropertyDescriptor ) { console .log("g(): called" ); }; } class C { @f () @g () method() {} }
装饰器调用顺序 参数装饰器,然后依次是方法装饰器,访问符装饰器,或属性装饰器应用到每个实例成员。 参数装饰器,然后依次是方法装饰器,访问符装饰器,或属性装饰器应用到每个静态成员。 参数装饰器应用到构造函数。 类装饰器应用到类。 类装饰器 注:类装饰器在类声明之前被声明(紧靠着类声明)。 类装饰器应用于类构造函数,可以用来监视,修改或替换类定义。 类装饰器不能用在声明文件中( .d.ts),也不能用在任何外部上下文中(比如 declare 的类)。类装饰器表达式会在运行时当作函数被调用,类的构造函数作为其唯一的参数。如果类装饰器返回一个值,它会使用提供的构造函数来替换类的声明。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @sealed class Greeter { greeting: string ; constructor (message: string ) { this .greeting = message; } greet() { return "Hello, " + this .greeting; } } function sealed (constructor: Function ) { Object .seal(constructor ); Object .seal(constructor.prototype); }
方法装饰器 注:方法装饰器声明在一个方法的声明之前(紧靠着方法声明)。 它会被应用到方法的 属性描述符上,可以用来监视,修改或者替换方法定义。 方法装饰器不能用在声明文件( .d.ts),重载或者任何外部上下文(比如 declare 的类)中。如果方法装饰器返回一个值,它会被用作方法的属性描述符。 方法装饰器表达式会在运行时当作函数被调用,传入下列 3 个参数:
对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。 成员的名字。 成员的属性描述符。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Greeter { greeting: string ; constructor (message: string ) { this .greeting = message; } @enumerable (false ) greet() { return "Hello, " + this .greeting; } } function enumerable (value: boolean ) { return function ( target: any , propertyKey: string , descriptor: PropertyDescriptor ) { descriptor.enumerable = value; }; }
访问器装饰器 注:访问器装饰器声明在一个访问器的声明之前(紧靠着访问器声明)。 访问器装饰器应用于访问器的 属性描述符并且可以用来监视,修改或替换一个访问器的定义。 访问器装饰器不能用在声明文件中(.d.ts),或者任何外部上下文(比如 declare 的类)里。 访问器装饰器表达式会在运行时当作函数被调用,传入下列 3 个参数:
对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。 成员的名字。 成员的属性描述符。
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 class Point { private _x: number ; private _y: number ; constructor (x: number , y: number ) { this ._x = x; this ._y = y; } @configurable (false ) get x() { return this ._x; } @configurable (false ) get y() { return this ._y; } } function configurable (value: boolean ) { return function ( target: any , propertyKey: string , descriptor: PropertyDescriptor ) { descriptor.configurable = value; }; }
属性装饰器 注:属性装饰器声明在一个属性声明之前(紧靠着属性声明)。 属性装饰器不能用在声明文件中(.d.ts),或者任何外部上下文(比如 declare 的类)里。 属性装饰器表达式会在运行时当作函数被调用,传入下列 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 class Greeter { @format ("Hello, %s" ) greeting: string ; constructor (message: string ) { this .greeting = message; } greet() { let formatString = getFormat(this , "greeting" ); return formatString.replace("%s" , this .greeting); } } import "reflect-metadata" ;const formatMetadataKey = Symbol ("format" );function format (formatString: string ) { return Reflect .metadata(formatMetadataKey, formatString); } function getFormat (target: any , propertyKey: string ) { return Reflect .getMetadata(formatMetadataKey, target, propertyKey); }
参数装饰器 注:参数装饰器声明在一个参数声明之前(紧靠着参数声明)。 参数装饰器应用于类构造函数或方法声明。 参数装饰器不能用在声明文件(.d.ts),重载或其它外部上下文(比如 declare 的类)里。参数装饰器只能用来监视一个方法的参数是否被传入。 参数装饰器表达式会在运行时当作函数被调用,传入下列 3 个参数:
对于静态成员来说是类的构造函数,对于实例成员是类的原型对象。 成员的名字。 参数在函数参数列表中的索引。
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 class Greeter { greeting: string ; constructor (message: string ) { this .greeting = message; } @validate greet(@required name: string ) { return "Hello " + name + ", " + this .greeting; } } import "reflect-metadata" ;const requiredMetadataKey = Symbol ("required" );function required ( target: Object , propertyKey: string | symbol, parameterIndex: number ) { let existingRequiredParameters: number [] = Reflect .getOwnMetadata(requiredMetadataKey, target, propertyKey) || []; existingRequiredParameters.push(parameterIndex); Reflect .defineMetadata( requiredMetadataKey, existingRequiredParameters, target, propertyKey ); } function validate ( target: any , propertyName: string , descriptor: TypedPropertyDescriptor<Function > ) { let method = descriptor.value; descriptor.value = function ( ) { let requiredParameters: number [] = Reflect .getOwnMetadata( requiredMetadataKey, target, propertyName ); if (requiredParameters) { for (let parameterIndex of requiredParameters) { if ( parameterIndex >= arguments .length || arguments [parameterIndex] === undefined ) { throw new Error ("Missing required argument." ); } } } return method.apply(this , arguments ); }; }