泛型
有时,我们需要某个函数可以同时支持多种类型,并且限制函数的返回类型和传入参数的类型存在某种关系。
举个简单的例子,创建一个函数,它会返回任何传入的它的值。
你可能会觉得用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 属性的数据