泛型(Generics)

泛型是只定义函数、接口或类时,不预先指定具体类型,而在使用的时候才指定类型。

  1. // 这个例子中,并没有准确的定义返回值类型,数组中每一项都应该是输入的value的类型
  2. function createArray(length: number, value: any): Array<any> {
  3. let result = [];
  4. for (let i = 0; i < length; i++) {
  5. result[i] = value;
  6. }
  7. return result;
  8. }
  9. createArray(3, 'x'); // ['x', 'x', 'x']

使用泛型来处理, 函数名后面添加 <T> 其中,T用来表示任意输入的类型

  1. function createArray<T>(length: number, value: T): Array<T> {
  2. let result: T[] = [];
  3. for (let i = 0; i < length; i++) {
  4. result[i] = value;
  5. }
  6. return result;
  7. }
  8. createArray(3, 'x'); // ['x', 'x', 'x']

多个类型参数

定义了一个 swap 函数,用来交换输入的元组

  1. function swap<T, U>(tuple: [T, U]): [U, T] {
  2. return [tuple[1], tuple[0]];
  3. }
  4. swap([7, 'seven']); // ['seven', 7]

泛型约束

在函数内部使用泛型变量时,由于预先不知道它是什么类型,不能随意操作其属性或方法

  1. function loggingIdentity<T>(arg: T): T {
  2. console.log(arg.length) // Error
  3. return arg
  4. }
  5. // 优化方法:使用接口对泛型进行约束
  6. interface Lengthwise {
  7. length: string
  8. }
  9. function loggingIdentity<T extends Lengthwise>(arg: T): T {
  10. console.log(arg.length) // Error
  11. return arg
  12. }

多个类型参数之间可以互相约束

  1. // 这个例子中,T继承自U,所以U的所有属性,T也有,否则会报错
  2. function copyFields<T extends U, U>(target: T, source: U): T {
  3. for (let id in source) {
  4. target[id] = (<T>source)[id];
  5. }
  6. return target;
  7. }
  8. let x = { a: 1, b: 2, c: 3, d: 4 };
  9. copyFields(x, { b: 10, d: 20 });

泛型接口

使用接口定义函数的形状

  1. interface SearchFunc {
  2. (source: string, subString: string): boolean;
  3. }
  4. let mySearch: SearchFunc;
  5. mySearch = function(source: string, subString: string) {
  6. return source.search(subString) !== -1;
  7. }

使用泛型来定义函数形状

  1. interface CreateArrayFunc {
  2. <T>(length: number, value: T): Array<T>;
  3. }
  4. let createArray: CreateArrayFunc;
  5. createArray = function<T>(length: number, value: T): Array<T> {
  6. let result: T[] = [];
  7. for (let i = 0; i < length; i++) {
  8. result[i] = value;
  9. }
  10. return result;
  11. }
  12. createArray(3, 'x'); // ['x', 'x', 'x']
  13. // 把泛型参数提前到接口名上
  14. interface CreateArrayFunc<T> {
  15. (length: number, value: T): Array<T>;
  16. }
  17. let createArray: CreateArrayFunc<any>;
  18. createArray = function<T>(length: number, value: T): Array<T> {
  19. let result: T[] = [];
  20. for (let i = 0; i < length; i++) {
  21. result[i] = value;
  22. }
  23. return result;
  24. }
  25. createArray(3, 'x'); // ['x', 'x', 'x']

泛型类

与泛型接口类似,泛型也可以用于类的类型定义中

  1. class GenericNumber<T> {
  2. zeroValue: T;
  3. add: (x: T, y: T) => T;
  4. }
  5. let myGenericNumber = new GenericNumber<number>();
  6. myGenericNumber.zeroValue = 0;
  7. myGenericNumber.add = function(x, y) { return x + y; };

泛型参数的默认类型

ts v2.3+,可以为泛型中的类型参数指定默认类型

  1. function createArray<T = string>(length: number, value: T): Array<T> {
  2. let result: T[] = [];
  3. for (let i = 0; i < length; i++) {
  4. result[i] = value;
  5. }
  6. return result;
  7. }

声明合并

如果定义了两个相同的函数、接口或类,那他们会合并为一个类型,函数的合并就是函数重载,这里就不介绍了。

接口的合并

  1. interface Alarm {
  2. price: nubmer;
  3. }
  4. interface Alarm {
  5. weight: nubmer;
  6. }
  7. // 相当于
  8. interface Alarm {
  9. price: nubmer;
  10. weight: nubmer;
  11. }

合并属性的 类型 必须是唯一的

  1. interface Alarm {
  2. price: number;
  3. }
  4. interface Alarm {
  5. price: number; // 虽然重复了,但是类型都是 `number`,所以不会报错
  6. weight: number;
  7. }
  8. interface Alarm {
  9. price: number;
  10. }
  11. interface Alarm {
  12. price: string; // 类型不一致,会报错
  13. weight: number;
  14. }
  15. // index.ts(5,3): error TS2403: Subsequent variable declarations must hav

方法的合并,与函数合并一样

  1. interface Alarm {
  2. price: number;
  3. alert(s: string): string;
  4. }
  5. interface Alarm {
  6. weight: number;
  7. alert(s: string, n: number): string;
  8. }
  9. // 相当于
  10. interface Alarm {
  11. price: number;
  12. weight: number;
  13. alert(s: string): string;
  14. alert(s: string, n: number): string;
  15. }

类的合并

与接口的合并规则一致