TS泛型定义实例


定义泛型函数

  • 为了确保传入的类型与返回的类型相同,使用类型变量T表示传入参数和返回值的类型
function identity<T>(arg: T): T {
  return arg
}
  • 泛型函数两种调用方式:
// 指定传入参数类型
// 事实没必要使用尖括号(<>)来明确地传入类型
let output = identity<string>("myString");
// 较常用,使用 类型推论,推断传入类型和返回类型
// 编译器可以查看myString的值,然后把T设置为它的类型
let output = identity("myString");

使用泛型变量

  • 明确表示传入的参数为T类型的数组,确保参数有.length这个属性
function loggingIdentity<T>(arg: T[]): T[] {
  console.log(arg.length);
  return arg;
}
// 也可以这样表示
function loggingIdentity<T>(arg: Array<T>): Array<T> {
  console.log(arg.length);
  return arg;
}

泛型类型

  • 泛型函数的类型,只需要将类型参数写在最前面,跟函数声明一样
function identity<T>(arg: T): T {
  return arg;
}

let myIdentity: <T>(arg: T) => T = identity;
// 也可以使用不同的泛型参数名,只要在数量上和使用方式上能对应上就可以
let myIdentity2: <U>(arg: U) => U = identity;
  • 可以使用带有调用签名的对象字面量来定义泛型函数
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;
  • 把泛型参数当作整个接口的一个参数,指定GenericIdentityFn的类型,这样接口里的其它成员也能知道这个参数的类型
interface GenericIdentityFn<T> {
    (arg: T): T;
}

function identity<T>(arg: T): T {
    return arg;
}

let myIdentity: GenericIdentityFn<number> = identity;

泛型类

  • 泛型类看上去与泛型接口差不多。 泛型类使用( <>)括起泛型类型,跟在类名后面
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; };
  • GenericNumber类的使用是十分直观的,并且你可能已经注意到了,没有什么去限制它只能使用number类型。 也可以使用字符串或其它更复杂的类型
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function(x, y) { return x + y; };

console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));

泛型约束

  • 定义一个接口来描述约束条件。 创建一个包含.length属性的接口,使用这个接口和extends关键字来实现约束
interface Lengthwise {
    length: number;
}

function loggingIdentity<T extends Lengthwise>(arg: T): T {
    console.log(arg.length);  
    return arg;
}

loggingIdentity("good") // √
loggingIdentity(123) // ×
loggingIdentity({length: 10, value: 3}) // √
loggingIdentity({}) // ×
loggingIdentity([]) // √

在泛型约束中使用类型参数

  • 声明一个类型参数,且它被另一个类型参数所约束。 比如,现在我们想要用属性名从对象里获取这个属性。 并且我们想要确保这个属性存在于对象 obj上,因此我们需要在这两个类型之间使用约束
function getProperty(obj: T, key: K) {
    return obj[key];
}

let x = { a: 1, b: 2, c: 3, d: 4 };

getProperty(x, "a");
getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.

  目录