being able to create a component that can work over a variety of types rather than a single one
还是为了复用
Hello World of Generics
function identity<T>(arg: T): T {return arg;}// 可能会想使用 any, 但是使用 any 就会丢失了类型信息function identity(arg: any): any {return arg;}// type of output will be 'string'// explicity set Tlet output = identity<string>("myString");// or ts automatically inference itlet output = identity("myString");
Working with Generic Type Variables
function loggingIdentity<T>(arg: T[]): T[] {console.log(arg.length); // Array has a .length, so no more errorreturn arg;}
Generic Types
// 泛型函数function identity<T>(arg: T): T {return arg;}let myIdentity: <T>(arg: T) => T = identity;// 不一定要用 T, 只要不冲突随便用, 只是约定俗成用 Tfunction identity<T>(arg: T): T {return arg;}let myIdentity: <U>(arg: U) => U = identity;// 使用带有 call signature 的对象字面量来定义泛型函数// 由此引出下面的带有泛型函数的接口function identity<T>(arg: T): T {return arg;}let myIdentity: {<T>(arg: T): T} = identity;// 有泛型函数的接口interface GenericIdentityFn {<T>(arg: T): T;}function identity<T>(arg: T): T {return arg;}let myIdentity: GenericIdentityFn = identity;// 泛型接口, 把泛型参数用到整个接口上interface GernericIndentityFn<T> {(arg: T): T;}function identity<T>(arg: T): T {return arg;}let myIdentity: GernericIndentityFn<number> = identity;
Generic Classes
就和泛型接口很像, 类型后面加上
注意只能用在类的 instance side
Generic classes are only generic over their instance side
class GenericNumber<T> {zeroValue: T;add: (x: T, y: T) => T;}// with numberlet myGenericNumber = new GenericNumber<number>();myGenericNumber.zeroValue = 0;myGenericNumber.add = function(x, y) { return x + y; };// with stringlet stringNumeric = new GenericNumber<string>();stringNumeric.zeroValue = "";stringNumeric.add = function(x, y) { return x + y; };
Generic Constraints
为 T 定义一个约束的集合
interface Lengthwise {length: number;}function loggingIdentity<T extends Lengthwise>(arg: T): T {console.log(arg.length); // Now we know it has a .length property, so no more errorreturn arg;}
用一个类型参数来约束另一个类型参数
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"); // okaygetProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.
using class types in generics
// 工厂函数function create<T>(c: {new(): T; }): T {return new c();}
更高级的运用, 构造函数和实例间的约束
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; // typechecks!createInstance(Bee).keeper.hasMask; // typechecks!
