泛型的作用是在运行时动态的指定变量的类型. 从而做到静态类型的最大代码复用.
泛型基本用法 没有使用泛型,代码会显的比较机械:不同类型的变量,虽然方法体一样,但我们还是会写两遍:
1 2 3 4 5 6 7 8 9 10 11 function operateNumber (a:number ,b:number ):number { let c:number ; return c } function operateString (a:string , b:string ):string { let c:string ; return c }
使用了泛型之后,我们可以做的代码复用了!
1 2 3 4 5 6 7 8 function operate <T >(a:T,b:T ):T { let c:T return c } operate(1 ,2 ) operate('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 57 58 59 class Queue { private data = []; push = item => this .data.push(item); pop = () => this .data.shift(); } const queue = new Queue();queue.push(0 ); queue.push('1' ); console .log(queue.pop().toPrecision(1 ));console .log(queue.pop().toPrecision(1 )); class QueueNumber { private data = []; push = (item: number ) => this .data.push(item); pop = (): number => this .data.shift(); } const queue = new QueueNumber();queue.push(0 ); queue.push('1' ); class Queue <T > { private data: T[] = []; push = (item: T ) => this .data.push(item); pop = (): T | undefined => this .data.shift(); } const queue = new Queue<number >();queue.push(0 ); queue.push('1' ); function reverse <T >(items: T[] ): T [] { const toreturn = []; for (let i = items.length - 1 ; i >= 0 ; i--) { toreturn.push(items[i]); } return toreturn; } const sample = [1 , 2 , 3 ];let reversed = reverse(sample);reversed[0 ] = '1' ; reversed = ['1' , '2' ]; reversed[0 ] = 1 ; reversed = [1 , 2 ];
泛型约束 泛型约束,就是为没有确定的类型制定一定会具备的特性.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 function loggingIdentity <T >(arg: T ): T { console .log(arg.length); return arg; } interface Lengthwise { length : number ; } function loggingIdentity <T extends Lengthwise >(arg: T ): T { console .log(arg.length); return arg; } loggingIdentity(3 ); loggingIdentity({length : 10 , value : 3 });
在泛型约束中使用类型参数 你可以声明一个类型参数,且它被另一个类型参数所约束。 比如,现在我们想要用属性名从对象里获取这个属性。 并且我们想要确保这个属性存在于对象obj
上,因此我们需要在这两个类型之间使用约束。
1 2 3 4 5 6 7 8 function getProperty <T , K extends keyof T >(obj: T, key: K ) { return obj[key]; } let x = { a : 1 , b : 2 , c : 3 , d : 4 };getProperty(x, "a" ); getProperty(x, "m" );
在泛型里使用类类型 在TypeScript使用泛型创建工厂函数时,需要引用构造函数的类类型
1 2 3 function create <T >(c: {new (): T; } ): T { return new c(); }
一个更高级的例子,使用原型属性推断并约束构造函数与类实例的关系。
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 class BeeKeeper { hasMask : boolean ; } class ZooKeeper { nametag : string ; } class Animal { numLegs : number ; } class Bee extends Animal { keeper : BeeKeeper; } class Lion extends Animal { keeper : ZooKeeper; } function createInstance <A extends Animal >(c: new () => A ): A { return new c(); } createInstance(Lion).keeper.nametag; createInstance(Bee).keeper.hasMask;
泛型类 泛型常用于 class中,用以约束说明 变量类型.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class GenericNumber <T > { zeroValue : T; add: (x: T, y: T ) => T; } let myGenericNumber = new GenericNumber<number >();myGenericNumber.zeroValue = 0 ; myGenericNumber.add = function (x, y ) { return x + y; }; let stringNumeric = new GenericNumber<string >();stringNumeric.zeroValue = "" ; stringNumeric.add = function (x, y ) { return x + y; }; alert(stringNumeric.add(stringNumeric.zeroValue, "test" ));
高级用法 extends继承 泛型中可以用 extends 继承(约束)某个规定的类型.其他约束的作用.
1 2 3 function myGenericFunction <T extends string >(arg: T ): T { return arg; }
条件类型 将泛型作为三元运算符的条件:
1 type MyType<T> = T extends string ? boolean : number ;
映射类型 keyof
可以用于声明泛型的key, 从而实现对类型的编程效果.
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 type Partial<T> = { [P in keyof T]?: T[P]; }; type Required<T> = { [P in keyof T]-?: T[P]; }; type Readonly<T> = { readonly [P in keyof T]: T[P]; }; type Nullable<T> { [P in keyof T]: T[P] | null } type Proxy <T> = { get(): T set(value: T): void } type Proxify<T> = { [P in keyof T]: Proxy <T[P]> } function proxify (o: T ): Proxify <T > { } let proxyProps = proxify(props)