TypeScript 类、泛型的使用实践记录
探讨TypeScript中的泛型的使用方法和场景
1. 泛型的基本概念
泛型(Generics)是指在定义函数、接口或类时,不预先指定具体的类型,而是在使用时再指定类型的一种特性。通过使用泛型可以增加代码的可复用性,提高代码的灵活性。
2. 泛型的使用场景
- 数据结构的抽象化:通过使用泛型,我们可以编写出通用的数据结构,例如堆栈、队列或链表等。这样一来,我们可以将这些数据结构应用于不同的数据类型,并且保持代码的可重用性和类型安全性。
- 函数的通用化:使用泛型函数可以处理多种输入类型,从而提高代码的通用性和复用性。例如,可以编写一个泛型排序函数,使其适用于不同类型的数组排序。
- 接口和类的通用化:在定义接口和类时,使用泛型可以使其更加通用和灵活。可以在实例化时指定具体的类型,从而确保该接口或类仅适用于特定类型的对象。
- 第三方库的类型安全:当使用第三方JavaScript库时,可以通过为其编写类型声明文件来提供类型安全性。通过使用泛型,可以为这些库添加更详细和准确的类型信息。
3、泛型的使用方法
泛型函数
泛型函数可以接收任意类型的参数,并返回相同类型的结果。
typescript
function identity<T>(arg: T): T {
return arg;
}
let output = identity<string>("myString"); // 类型为 "string"
let output2 = identity<number>(100); // 类型为 "number"
泛型接口
泛型接口可以定义一个类型变量,然后在接口的多个属性中使用这个变量。
typescript
interface GenericIdentityFn<T> {
(arg: T): T;
}
function identityFn<T>(arg: T): T {
return arg;
}
let myIdentity: GenericIdentityFn<number> = identityFn;
泛型类
泛型类允许你在类的层面上定义类型变量。
typescript
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; };
泛型约束
你可以为泛型添加约束,以确保它们符合特定的形状或接口。
typescript
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 }); // OK
泛型类型别名
你可以创建泛型类型别名来为复杂类型创建别名。
typescript
type Container<T> = {
value: T;
};
const myContainer: Container<number> = { value: 1 };
泛型联合类型
你可以创建泛型联合类型,以允许函数接受多种类型的参数。
typescript
function padLeft<T extends string | number>(input: T, padding: string | number): string {
if (typeof input === "number") input = input.toString();
if (typeof padding === "number") padding = padding.toString();
return padding + input;
}
padLeft("Ex", 5); // 返回 "5Ex"
padLeft(2, "Ex"); // 返回 "Ex2"
泛型工具类型
TypeScript 提供了一些内置的泛型工具类型,如 Partial<T>, Readonly<T>, Pick<T, K> 等,用于创建类型的子集或选择类型的某些属性。
typescript
type PartialPoint = Partial<{ x: number; y: number }>;
const point: PartialPoint = { x: 1 }; // OK
泛型条件类型
条件类型允许你基于类型系统的条件逻辑来创建新的类型。
typescript复制
type IsNumber<T> = T extends number ? "Yes" : "No";
type A = IsNumber<5>; // "Yes"
type B = IsNumber<"5">; // "No"
如何使用类型约束来增加代码的灵活性和安全性
1. 泛型约束的基本使用
在使用泛型时,我们经常需要限制泛型类型必须满足某些条件。这就是泛型约束的作用。通过extends关键字,我们可以指定泛型类型必须包含某些属性或方法。这种约束确保了我们可以安全地访问这些必需的成员。
2. 泛型约束的多重约束
在某些场景下,我们可能需要类型同时满足多个接口的要求。TypeScript允许我们使用交叉类型来实现多重约束,这为类型系统提供了更强的表达能力。
3. 泛型约束的实际应用
- 确保类型具有特定属性:例如,确保传入的类型具有
length属性时,可以这样做:这样,我们可以确保interface Lengthwise { length: number; } function loggingIdentity<T extends Lengthwise>(arg: T): T { console.log(arg.length); // 现在我们知道arg一定有length属性 return arg; }arg一定有length属性,增强了类型安全性。
通过合理使用泛型和类型约束,我们可以编写出更加健壮、可维护和易于理解的TypeScript代码。