在本章中,我们将探讨如何使用泛型来增强Deno中的类型系统。泛型允许我们编写更加灵活和可重用的代码,同时保持类型安全。
什么是泛型?
泛型是一种编程技术,它允许你编写可以适用于多种数据类型的代码。通过使用泛型,我们可以创建能够处理任意类型数据的函数、类或接口,而无需牺牲类型安全性。
泛型函数
定义泛型函数
泛型函数允许我们在定义函数时指定一个或多个类型参数,这些类型参数可以在函数体中使用。这样,我们可以根据需要传入不同的类型,同时保持编译时的类型检查。
function identity<T>(arg: T): T {
return arg;
}在这个例子中,identity 函数接受一个类型为 T 的参数,并返回一个类型为 T 的值。这里的 T 就是一个类型参数,代表任何类型。
使用泛型函数
我们可以使用任何类型调用这个泛型函数:
let output = identity<string>("myString"); // 类型为 string
let output2 = identity<number>(99); // 类型为 number或者,如果我们不指定类型,TypeScript 会自动推断类型:
let output3 = identity("hello world"); // 类型为 string多个类型参数
我们也可以为函数定义多个类型参数:
function swap<T, U>(tuple: [T, U]): [U, T] {
return [tuple[1], tuple[0]];
}
let result = swap([7, "seven"]); // 结果是 ["seven", 7]泛型类
泛型类的定义
泛型类允许我们在类定义中指定类型参数。这使得类的实例化可以使用不同的类型。
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 类使用了一个类型参数 T。当我们创建该类的一个实例时,必须提供一个具体类型。
泛型接口
泛型接口的定义
接口也可以是泛型的,这意味着接口可以描述具有特定类型的属性或方法。
interface Pair<T, U> {
first: T;
second: U;
}
let myPair: Pair<string, number> = {first: "hello", second: 7};在这个例子中,Pair 接口有两个类型参数 T 和 U,分别表示 first 和 second 属性的类型。
泛型约束
约束泛型类型
有时候我们需要限制类型参数可以使用的类型。例如,如果我们要操作数组,可能希望类型参数支持某些方法(如 length 属性)。为此,我们可以使用泛型约束。
// www.javascriptcn.com code example
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 现在我们知道有 .length 属性了
return arg;
}
loggingIdentity({length: 10, value: 3}); // 正确在这个例子中,我们定义了一个接口 Lengthwise,它有一个 length 属性。然后我们定义了一个 loggingIdentity 函数,它接受一个类型参数 T,但要求 T 必须满足 Lengthwise 接口。这样,我们就可以在函数体内使用 arg.length 属性了。
泛型实用技巧
默认类型
使用默认类型
有时我们可能想要给泛型参数提供一个默认类型。当用户没有提供类型参数时,就使用默认类型。
// www.javascriptcn.com code example
function createArray<T = string>(length: number, value: T): T[] {
let result: T[] = [];
for (let i = 0; i < length; i++) {
result[i] = value;
}
return result;
}
console.log(createArray(3, 'x')); // ['x', 'x', 'x']在这个例子中,如果用户没有指定类型参数,那么 createArray 函数将使用 string 作为默认类型。
泛型工具类型
利用工具类型
TypeScript 提供了一些内置的工具类型,它们可以帮助我们更方便地操作泛型类型。例如,Partial 工具类型可以将对象的所有属性变为可选的。
// www.javascriptcn.com code example
type Partial<T> = {
[P in keyof T]?: T[P];
};
interface User {
name: string;
age: number;
}
type PartialUser = Partial<User>;
let user: PartialUser = { name: "Alice" }; // 允许只设置部分属性在这个例子中,我们定义了一个 PartialUser 类型,它是 User 类型的一个变体,其中所有属性都是可选的。
总结
泛型是 TypeScript 中非常强大的功能,它使我们的代码更加灵活和可重用。通过合理使用泛型,我们可以创建出既强大又类型安全的程序。在接下来的部分中,我们将继续探索更多关于泛型的高级用法。