在TypeScript中,泛型(Generics)是一种强大的工具,用于创建可重用的、类型安全的代码。它允许我们在定义函数、类或接口时使用类型参数,以便在使用时指定具体的类型。
1. 函数泛型:
可以在函数定义中使用泛型来表示参数类型或返回值类型的灵活性。例如,我们可以编写一个通用的identity函数,它接受一个参数并返回相同的值,但可以适用于不同的类型:
function identity<T>(arg: T): T {
return arg;
}
let result = identity<string>("Hello");
2. 类泛型:
类也可以使用泛型来增加灵活性。例如,我们可以创建一个泛型的Box类,它可以存储不同类型的值:
class Box<T> {
private value: T;
constructor(value: T) {
this.value = value;
}
getValue(): T {
return this.value;
}
}
let box1 = new Box<number>(10);
let box2 = new Box<string>("Hello");
3. 接口泛型:
接口也可以使用泛型来定义灵活的类型。例如,我们可以创建一个泛型的List接口,表示一个具有不同类型元素的列表:
interface List<T> {
length: number;
getItem(index: number): T;
addItem(item: T): void;
}
class MyList<T> implements List<T> {
private items: T[] = [];
length: number = 0;
getItem(index: number): T {
return this.items[index];
}
addItem(item: T): void {
this.items.push(item);
this.length++;
}
}
let myList = new MyList<number>();
myList.addItem(10);
myList.addItem(20);
泛型的使用可以增加代码的灵活性和安全性,具体体现在以下几个方面:
1. 类型安全性: 泛型可以在编译时提供类型检查,确保代码在使用时符合预期的类型。这可以避免在运行时出现类型错误。
2. 代码重用性: 泛型允许我们编写通用的代码,可以在不同的类型上进行操作,从而提高代码的重用性和可维护性。
3. 抽象数据类型: 泛型可以用于创建抽象的数据类型,使得代码更加通用和可扩展。通过泛型,我们可以定义适用于不同类型的数据结构和算法。
4. 接口和函数的灵活性: 使用泛型可以定义灵活的接口和函数,使其适用于不同类型的参数和返回值,从而增加代码的灵活性和可扩展性。
泛型约束即是对泛型的类型进行约束控制,如限制为object类型或指定接口类型。当在函数里使用泛型参数的属性或者方法时,就需要对泛型进行约束。
1.接口约束
interface Lengthwise {
length: number;
}
function loggingIdentity<T extends Lengthwise>(arg: T): T {
console.log(arg.length); // 如果没有Lengthwise泛型约束,会报错Error: T doesn't have .length
return arg;
}
2.object约束
function getKeys<T extends object>(data:T) :string[] {
const keys:Array<string> = Object.keys(data)
return keys
}
工具
TypeScript提供了一些内置的泛型工具类型,例如Partial、Readonly、Pick和Record等,它们可以帮助我们更方便地操作和处理复杂的类型。这些工具类型可以用来创建部分可选的类型、只读的类型、从现有类型中选取部分属性或将一个键值对列表转换为一个类型。通过使用这些工具类型,我们可以更加简洁和灵活地定义和操作复杂的类型。