给团队做次TypeScript分享(五)—— 泛型

168 阅读2分钟

泛型

有时,我们需要某个函数可以同时支持多种类型,并且限制函数的返回类型和传入参数的类型存在某种关系。

举个简单的例子,创建一个函数,它会返回任何传入的它的值。

你可能会觉得用any

function returnAnything(val:any) : any{
  return val
}

可是,用 any 的话无法保证函数的返回类型与参数类型一致

于是,我们就需要泛型

在 ts 中,我们可以使用类型变量,这是一种特殊的变量,用于表示类型而不是值,比如上面的例子中,我们可以

function returnAnything<T>(val:T) : T{
  return val
}

然后,我们可以这样使用函数

returnAnything<number>(11)

也可以不用传 < T >,直接使用

returnAnything(11)
// 类型推论,ts编译器会根据传入的参数自动确认 T 的类型

泛型接口

可以把泛型参数当作整个接口的一个参数

interface GenericIReturnAnythingFn<T> {
  (arg: T): T;
}

let returnAnything: GenericIReturnAnythingFn<number> = function (val) {
  return val;
};

泛型类

class StyleInfo<T> {
  width: T | undefined;
  getColor: ((color: T) => T) | undefined;
}

let myStyle = new StyleInfo<string>();
myStyle.width = "100px";
myStyle.getColor = (val) => val;

let additionStyle = new StyleInfo<number>();
additionStyle.width = 100;

类有两部分:静态部分和实例部分。 泛型类指的是实例部分的类型,类的静态属性不能使用这个泛型类型。

class StyleInfo<T> {
  static eleName: T | undefined; // error 静态成员不能引用类类型参数
}

泛型中使用类类型

class User {
  name: string = "jack";
}

function create<T>(c: { new (): T }): T {
  return new c();
}

console.log(create(User).name); // jack

泛型约束

有时我们不想 泛型参数 可以传入所有类型,想要对可传入的类型做一些约束

可以使用 extends 关键字来实现,这里的 extends 并非是继承的意思,而是约束类型

function returnAnything<T extends { data: string }>(val: T): string {
  return val.data;
}

returnAnything({ data: 'ok' }) // ok
returnAnything(100) // error

如以上的例子,只能传入有 data 属性的数据