• 泛型(Generics)是指在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性
  • 泛型T作用域只限于函数内部使用

    泛型函数

    首先,我们来实现一个函数 createArray,它可以创建一个指定长度的数组,同时将每一项都填充一个默认值
    1. function createArray(length: number, value: any):Array<any> {
    2. const arr = [];
    3. for (let i = 0; i < length; i++) {
    4. arr[i] = value;
    5. }
    6. return arr;
    7. }
    8. console.log(createArray(5, 2)); // [ 2, 2, 2, 2, 2 ]
    使用泛型 ```typescript function createArray(length: number, value: T): Array { const arr = []; for (let i = 0; i < length; i++) { arr[i] = value; } return arr; }

console.log(createArray(2, 3)); // [ 3, 3 ] console.log(createArray(2, ‘hello’)); // [ ‘hello’, ‘hello’ ]

  1. <a name="tQSFr"></a>
  2. # 类数组
  3. 类数组(Array-like Object)不是数组类型,比如 arguments
  4. ```typescript
  5. let root = document.getElementById('root');
  6. let children: HTMLCollection = (root as HTMLElement ).children;
  7. children.length;
  8. let nodeList: NodeList = (root as HTMLElement).childNodes;
  9. nodeList.length;

泛型类

  1. class MyArray<T> {
  2. private arr: T[] = []
  3. add(val: T) {
  4. this.arr.push(val);
  5. }
  6. }
  7. const arr1 = new MyArray<number>();
  8. arr1.add(1)
  9. // Argument of type 'string' is not assignable to parameter of type 'number'.
  10. // arr.add('')
  11. const arr2 = new MyArray<string>();
  12. arr2.add('hello')

泛型和 new

  1. class Person { }
  2. class Animal {}
  3. function factory<T>(type: { new(): T }): T{
  4. return new type();
  5. }
  6. factory(Person);
  7. factory(Animal);

泛型接口

泛型接口可以用来约束函数

  1. interface Sum {
  2. <T>(a: T, b: T): T;
  3. }
  4. const sum: Sum = function <T>(a: T, b: T): T {
  5. // 报错:Operator '+' cannot be applied to types 'T' and 'T'. 这是因为 a,b 可能是任意类型,不一定能使用加号
  6. // return a + b;
  7. return a;
  8. }
  9. // Argument of type 'string' is not assignable to parameter of type 'number'.
  10. // sum<number>(1, '');
  11. sum<number>(1, 2);

定义接口的时候也可以指定泛型

  1. interface Sum<T> {
  2. (a: T, b: T): T;
  3. }
  4. const sum: Sum<number> = function(a: number, b: number): number {
  5. return a;
  6. };
  1. interface Sum<T> {
  2. <U>(a:T, b:T):U
  3. }
  4. const sum: Sum<number> = function <U>(a: number, b: number): U { return a as any };
  5. sum<number>(1, 2);

多个类型参数

泛型可以有多个

  1. function swap<A, B>(tuple: [A, B]): [B, A] {
  2. return [tuple[1], tuple[0]];
  3. }
  4. console.log(swap([1, 'a'])); // ['a', 1]
  1. interface Sum<T> {
  2. <U>(a:T, b:T):U
  3. }
  4. const sum: Sum<number> = function <U>(a: number, b: number): U { return a as any };
  5. sum<number>(1, 2);

默认泛型类型

  1. function createArr<T = number>(length: number, val: T): Array<T> {
  2. const arr = [];
  3. for (let i = 0; i < length; i++) {
  4. arr[i] = val;
  5. }
  6. return arr;
  7. }
  8. createArr(1, 2)
  9. createArr<string>(1, 'a')

泛型约束

在函数中使用泛型的时候,由于预先并不知道泛型的类型,所以不能随意访问相应类型的属性或方法。

  1. function logge1<T>(val: T) {
  2. // Property 'length' does not exist on type 'T'.
  3. // console.log(val.length);
  4. }
  5. interface Length {
  6. // length 属性
  7. length: number;
  8. }
  9. function logger2<T extends Length>(val: T) {
  10. console.log(val.length);
  11. }
  12. logger2<string>('a');
  13. // Type 'number' does not satisfy the constraint 'Length'.
  14. // logger2<number>(1);
  15. const obj = { name: 'f', age: 18, length: 1};
  16. type O = typeof obj;
  17. logger2<O>(obj);
  1. class GrandFather {
  2. grandFather = '';
  3. }
  4. class Father extends GrandFather {
  5. father = '';
  6. }
  7. class Child extends Father {
  8. child = '';
  9. }
  10. let grandFather = new GrandFather();
  11. let father = new Father();
  12. let child = new Child();
  13. // Property 'child' is missing in type 'Father' but required in type 'Child'.
  14. // child = father;
  15. // 判断兼容和不兼容跟 extends 继承没有一点关系,只看形状有没有对应
  16. father = child;
  17. function get<T extends Father>() { }
  18. get<Child>()
  19. get<Father>()
  20. // Type 'GrandFather' does not satisfy the constraint 'Father'.Property 'father' is missing in type 'GrandFather' but required in type 'Father'.
  21. // get<GrandFather>()

compose

  1. type Func<T extends any[], R> = (...a: T) => R;
  2. console.log(compose()('f')); // 'f'
  3. function fn1(str:string):string { return str + 'i'; }
  4. console.log(compose(fn1)('f')); // 'fi'
  5. function fn2(str: string): string { return str + 'e'; }
  6. console.log(compose(fn1, fn2)('f')) // 'fei'
  7. export default function compose(): <R>(a: R) => R;
  8. export default function compose<F extends Function>(f: F): F;
  9. /* two functions */
  10. export default function compose<A, T extends any[], R>(f1: (a: A) => R, f2: Func<T, A>): Func<T, R>;
  11. /* three functions */
  12. export default function compose<A, B, T extends any[], R>(f1: (b: B) => R, f2: (a: A) => B, f3: Func<T, A>): Func<T, R>;
  13. /* four functions */
  14. export default function compose<A, B, C, T extends any[], R>(
  15. f1: (c: C) => R,
  16. f2: (b: B) => C,
  17. f3: (a: A) => B,
  18. f4: Func<T, A>
  19. ): Func<T, R>;
  20. /* rest */
  21. export default function compose<R>(f1: (a: any) => R, ...funcs: Function[]): (...args: any[]) => R;
  22. export default function compose<R>(...funcs: Function[]): (...args: any[]) => R;
  23. export default function compose(...funcs: Function[]) {
  24. if (funcs.length === 0) {
  25. return <T>(arg: T) => arg;
  26. }
  27. if (funcs.length === 1) {
  28. return funcs[0];
  29. }
  30. return funcs.reduce((a, b) => (...args: any) => a(b(...args)));
  31. }
  1. function add<T extends string | number>(x: T, y: T): T {
  2. return x + y;
  3. }
  4. add<string>("a", "b");
  5. add<number>(5, 3);
  6. add("a", "b");
  7. add(5, 3);

上述代码会报错:Operator '+' cannot be applied to types 'T' and 'T'. 我们可以改成下面这样:

  1. function addString<T extends string>(x: T, y: T): string {
  2. return x + y;
  3. }
  4. function addNum<T extends number>(x: T, y: T): number {
  5. let a = x * y;
  6. let b = x - y;
  7. let z = x++;
  8. return x + y;
  9. }
  10. addString("a", "b");
  11. addNum(1, 2);

泛型类型别名

泛型类型别名可以表达更复杂的类型

  1. type Arr<T> = { arr: T[]} | T[];
  2. const arr1: Arr<number> = [1, 2];
  3. const arr2: Arr<string> = { arr: [] };

泛型接口 vs 泛型类型

  • 接口创建了一个新的名字,它可以在其他任意地方被调用。而类型别名并不创建新的名字,例如报错信息就不会使用别名
  • 类型别名不能被 extends和 implements,这时我们应该尽量使用接口代替类型别名
  • 当我们需要使用联合类型或者元组类型的时候,类型别名会更合适
  • 能使用 interface 实现的不用 type