being able to create a component that can work over a variety of types rather than a single one

还是为了复用

Hello World of Generics

  1. function identity<T>(arg: T): T {
  2. return arg;
  3. }
  4. // 可能会想使用 any, 但是使用 any 就会丢失了类型信息
  5. function identity(arg: any): any {
  6. return arg;
  7. }
  8. // type of output will be 'string'
  9. // explicity set T
  10. let output = identity<string>("myString");
  11. // or ts automatically inference it
  12. let output = identity("myString");

Working with Generic Type Variables

  1. function loggingIdentity<T>(arg: T[]): T[] {
  2. console.log(arg.length); // Array has a .length, so no more error
  3. return arg;
  4. }

Generic Types

  1. // 泛型函数
  2. function identity<T>(arg: T): T {
  3. return arg;
  4. }
  5. let myIdentity: <T>(arg: T) => T = identity;
  6. // 不一定要用 T, 只要不冲突随便用, 只是约定俗成用 T
  7. function identity<T>(arg: T): T {
  8. return arg;
  9. }
  10. let myIdentity: <U>(arg: U) => U = identity;
  11. // 使用带有 call signature 的对象字面量来定义泛型函数
  12. // 由此引出下面的带有泛型函数的接口
  13. function identity<T>(arg: T): T {
  14. return arg;
  15. }
  16. let myIdentity: {<T>(arg: T): T} = identity;
  17. // 有泛型函数的接口
  18. interface GenericIdentityFn {
  19. <T>(arg: T): T;
  20. }
  21. function identity<T>(arg: T): T {
  22. return arg;
  23. }
  24. let myIdentity: GenericIdentityFn = identity;
  25. // 泛型接口, 把泛型参数用到整个接口上
  26. interface GernericIndentityFn<T> {
  27. (arg: T): T;
  28. }
  29. function identity<T>(arg: T): T {
  30. return arg;
  31. }
  32. let myIdentity: GernericIndentityFn<number> = identity;

Generic Classes

就和泛型接口很像, 类型后面加上
注意只能用在类的 instance side

Generic classes are only generic over their instance side

  1. class GenericNumber<T> {
  2. zeroValue: T;
  3. add: (x: T, y: T) => T;
  4. }
  5. // with number
  6. let myGenericNumber = new GenericNumber<number>();
  7. myGenericNumber.zeroValue = 0;
  8. myGenericNumber.add = function(x, y) { return x + y; };
  9. // with string
  10. let stringNumeric = new GenericNumber<string>();
  11. stringNumeric.zeroValue = "";
  12. stringNumeric.add = function(x, y) { return x + y; };

Generic Constraints

为 T 定义一个约束的集合

  1. interface Lengthwise {
  2. length: number;
  3. }
  4. function loggingIdentity<T extends Lengthwise>(arg: T): T {
  5. console.log(arg.length); // Now we know it has a .length property, so no more error
  6. return arg;
  7. }

用一个类型参数来约束另一个类型参数

  1. function getProperty<T, K extends keyof T>(obj: T, key: K) {
  2. return obj[key];
  3. }
  4. let x = { a: 1, b: 2, c: 3, d: 4 };
  5. getProperty(x, "a"); // okay
  6. getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.

using class types in generics

  1. // 工厂函数
  2. function create<T>(c: {new(): T; }): T {
  3. return new c();
  4. }

更高级的运用, 构造函数和实例间的约束

  1. class BeeKeeper {
  2. hasMask: boolean;
  3. }
  4. class ZooKeeper {
  5. nametag: string;
  6. }
  7. class Animal {
  8. numLegs: number;
  9. }
  10. class Bee extends Animal {
  11. keeper: BeeKeeper;
  12. }
  13. class Lion extends Animal {
  14. keeper: ZooKeeper;
  15. }
  16. function createInstance<A extends Animal>(c: new () => A): A {
  17. return new c();
  18. }
  19. createInstance(Lion).keeper.nametag; // typechecks!
  20. createInstance(Bee).keeper.hasMask; // typechecks!