定义泛型函数
- 为了确保传入的类型与返回的类型相同,使用
类型变量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'.