本篇整理自 TypeScript Handbook 中 「Generics」 章节。
泛型- 带参数的类型
Generics 初探
类型变量是一种用在类型而非值上的特殊的变量。是一种可以捕获参数类型的方式,然后再用它表示返回值的类型
// 定义
function identity<Type>(arg: Type): Type {
return arg;
}
// 使用
// 方式1 --- 是传入所有的参数,包括类型参数 === 类型参数定义在<>中
let output = identity<string>("myString")
// 方式2 --- 类型参数推断 --- 常见
let output = identity("myString");
泛型函数的形式就跟其他非泛型函数的一样,都需要先列一个类型参数列表
function identity<Type>(arg: Type): Type {
return arg;
}
// 函数表达式
let myIdentity: <Type>(arg: Type) => Type = identity;
// 调用签名
let myIdentity: { <Type>(arg: Type): Type } = identity;
// 使用调用签名定义函数接口
interface GenericIdentityFn {
<Type>(arg: Type): Type;
}
function identity<Type>(arg: Type): Type {
return arg;
}
let myIdentity: GenericIdentityFn = identity;
注意,TypeScript中不存在泛型枚举类型和泛型命名空间
泛型类
泛型类写法上类似于泛型接口。在类名后面,使用尖括号中 <> 包裹住类型参数列表
class GenericNumber<NumType> {
zeroValue: NumType;
add: (x: NumType, y: NumType) => NumType;
}
一个类它的类型有两部分:静态部分和实例部分。泛型类仅仅对实例部分生效
所以当我们使用类的时候,注意静态成员并不能使用类型参数
class user<NumType> {
username: NumType // success
static username: NumType; // error
constructor(username: NumType) {
this.username = username
}
}
泛型约束
可以在泛型中使用这个接口和 extend关键词实现约束
interface Lengthwise {
length: number;
}
function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
console.log(arg.length); // Now we know it has a .length property, so no more error
return arg;
}
在泛型约束中使用类型参数
可以声明一个类型参数,这个类型参数被其他类型参数所约束
function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a"); // success
getProperty(x, "m"); // error
在泛型中使用类类型
当使用工厂模式创建实例的时候,有必要通过他们的构造函数推断出类的类型
function create<Type>(c: { new (): Type }): Type {
return new c();
}
下面是一个更复杂的例子,使用原型属性推断和约束,构造函数和类实例的关系
class BeeKeeper {
hasMask: boolean = true;
}
class ZooKeeper {
nametag: string = "Mikle";
}
class Animal {
numLegs: number = 4;
}
class Bee extends Animal {
keeper: BeeKeeper = new BeeKeeper();
}
class Lion extends Animal {
keeper: ZooKeeper = new ZooKeeper();
}
function createInstance<A extends Animal>(c: new () => A): A {
return new c();
}
createInstance(Lion).keeper.nametag;
createInstance(Bee).keeper.hasMask;