一、介绍
类型变量,它是一种特殊的变量,只用于表示类型而不是值。
function identity<T>(arg: T): T { // 声明带有泛型的函数
return arg;
}
二、使用
-
传入所有的参数,包含类型参数:
let output = identity<string>("myString"); // type of output will be 'string'
-
类型推论
let output = identity("myString"); // type of output will be 'string'
编译器可以查看
myString
的值,然后把T
设置为它的类型。 类型推论帮助我们保持代码精简和高可读性。如果编译器不能够自动地推断出类型的话,只能像上面那样明确的传入T的类型,在一些复杂的情况下,这是可能出现的。
三、类型
-
类型参数在最前面。
function identity<T>(arg: T): T { return arg; } let myIdentity: <T>(arg: T) => T = identity;
-
可以使用不同的泛型参数名。
function identity<T>(arg: T): T { return arg; } let myIdentity: <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;
-
泛型接口参数。
// 把参数放在调用签名里 interface GenericIdentityFn { <T>(arg: T): T; } function identity<T>(arg: T): T { return arg; } let myIdentity: GenericIdentityFn = identity; // 把参数放在调用接口上 interface GenericIdentityFn<T> { (arg: T): T; } function identity<T>(arg: T): T { return arg; } let myIdentity: GenericIdentityFn<number> = identity; // 锁定了之后代码里使用的类型
除了泛型接口,我们还可以创建泛型类。
注意,无法创建泛型枚举和泛型命名空间。
四、泛型类
泛型类使用( <>)括起泛型类型,跟在类名后面。
```ts
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; };
```
注意:泛型类指的是实例部分的类型,所以类的静态属性不能使用这个泛型类型。
这里意思是泛型类约束的是除类静态部分其他的属性部分。
五、泛型约束
-
限制传入参数的类型。
interface Lengthwise { // 创建一个包含 .length属性的接口 length: number; } function loggingIdentity<T extends Lengthwise>(arg: T): T { // 使用这个接口和extends关键字来实现约束 console.log(arg.length); // Now we know it has a .length property, so no more error return arg; }
-
在泛型约束中使用类型参数
两个类型之间使用约束function getProperty(obj: T, key: K) { return obj[key]; } let x = { a: 1, b: 2, c: 3, d: 4 }; getProperty(x, "a"); // okay getProperty(x, "m"); // error: Argument of type 'm' isn't assignable to 'a' | 'b' | 'c' | 'd'.
-
在泛型里使用类类型
(1) 工厂函数function create<T>(c: {new(): T; }): T { return new c(); } // test class Test { name: string = 'test'; } let a = create(Test) console.log(a, 123);
(2) 原型属性推断并约束构造函数与类实例的关系
class BeeKeeper { hasMask: boolean = false; } class ZooKeeper { nametag: string = '333'; } class Animal { numLegs: number = 1; } 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(); } var a = createInstance(Lion).keeper.nametag; // typechecks! // createInstance(Bee).keeper.hasMask; // typechecks! console.log(a, 123); function create<T>(c: {new(): T; }): T { return new c(); }