TypeScript 泛型(Generics)
泛型是 TypeScript 最强大的特性之一,它允许我们在定义函数、接口或类的时候,不预先指定具体的类型,而在使用的时候再指定类型的一种特性。
1. 泛型函数
让我们从一个简单的泛型函数开始:
function identity<T>(arg: T): T {
return arg;
}
let output1 = identity<string>("myString"); // 类型为 'string'
let output2 = identity(123); // 类型推断为 'number'
在这个例子中:
<T>
定义了一个类型变量T
。- 这个
T
允许我们捕获用户提供的类型。 - 我们可以明确指定类型,如
identity<string>
,或让 TypeScript 自动推断类型。
2. 泛型接口
泛型也可以用于接口定义:
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identity<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identity;
这里我们创建了一个泛型接口,它描述了一个泛型函数。
3. 泛型类
泛型类看起来与泛型接口差不多:
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; };
4. 泛型约束
有时我们想限制泛型可以接受的类型,这时可以使用泛型约束:
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 现在我们知道arg具有length属性
return arg;
}
loggingIdentity({length: 10, value: 3});
// loggingIdentity(3); // 错误,数字没有length属性
这个例子展示了如何使用 extends
关键字来约束泛型类型必须符合某个接口。
5. 在泛型约束中使用类型参数
你可以声明一个类型参数,这个类型参数被其他类型参数约束:
function getProperty<T, K extends keyof T>(obj: T, key: K) {
return obj[key];
}
let x = { a: 1, b: 2, c: 3, d: 4 };
getProperty(x, "a"); // 正确
// getProperty(x, "m"); // 错误:参数 "m" 不能赋给类型 "a" | "b" | "c" | "d"
这个例子使用了 keyof T
来获取 T
的所有属性名,然后使用 extends
来确保 K
是 T
的有效属性名。
6. 泛型中的类类型
在 TypeScript 使用泛型创建工厂函数时,需要引用构造函数的类类型:
function create<T>(c: {new(): T; }): T {
return new c();
}
这个例子展示了如何使用泛型来创建一个实例。
7. 多重类型泛型
泛型可以接受多个类型参数:
function pair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
let p = pair<string, number>('hello', 42); // [string, number]
这些是 TypeScript 中泛型的主要概念和用法。泛型为我们提供了一种方式来创建可重用的组件,这些组件可以与多种类型一起工作,而不是单一类型。这极大地增强了代码的灵活性和可重用性。
学起来还是挺多的。。。