在TypeScript中,泛型(Generics)是一个非常强大的特性,它允许我们编写可以在多种类型上工作的可重用的代码。使用泛型可以提高代码的灵活性和安全性,同时还能增加代码的可读性和可维护性。 泛"就是广泛的意思,"型"就是数据类型。顾名思义,泛型就是适用于多种数据类型的一种类型。但是其它类型的数据,比如string、boolean或者自定义的Teacher等类型就没有办法使用这个函数。虽然any可以解决这个问题,但是函数参数和返回值定义为any的时候,具体的类型信息就已经丢失了。比如传入的是一个number,那么我们希望返回的并不是any类型,而是number类型。所以,我们需要在函数中可以捕获到参数的类型是number,并且同时使用它来作为返回值的类型。因此需要在这里使用一种特性的变量 - 类型变量(type variable),它作用于类型,而不是值。 我们可以把Type看做额外的一个参数,把类型参数化。它可以做到, 在定义这个函数时, 不决定这些参数的类型, 而是让调用者以参数的形式告知, 这里的函数参数应该是什么类型。 传入泛型的方式函数定义时,<>的位置就是之后泛型的传入位置,比如上面函数的。 传入泛型时,只要把具体的泛型传递给即可。这样函数定义时的,函数参数,和函数返回值的T类型,都会变成传入的具体参数类型。 它能够帮助我们构建出复用性更强的代码。 下面是一些使用泛型的常见场景和实践记录:
- 创建可重用的数据结构:泛型可以用于创建可重用的数据结构,如数组、链表等。例如,我们可以创建一个泛型数组类,可以存储任意类型的元素: class Array { private data: T[] = [];
push(item: T) { this.data.push(item); }
pop(): T | undefined {
return this.data.pop();
}
}
const numberArray = new Array();
numberArray.push(1);
numberArray.push(2);
console.log(numberArray.pop()); // 2
const stringArray = new Array();
stringArray.push("hello");
stringArray.push("world");
console.log(stringArray.pop()); // "world"
2. 编写可复用的函数:泛型函数可以在多种类型上工作,并且可以根据参数的类型进行类型推断。例如,我们可以编写一个泛型的identity函数,它接受一个参数并返回该参数:
function identity(value: T): T {
return value;
}
const result = identity("hello");
console.log(result); // "hello"
3.对象属性的约束:泛型可以用于约束对象的属性。例如,我们可以创建一个泛型接口Lengthwise,它要求对象具有length属性:
interface Lengthwise {
length: number;
}
function printLength(obj: T) {
console.log(obj.length);
}
printLength("hello"); // 5
printLength([1, 2, 3]); // 3
4.多个泛型参数:可以在函数或类中使用多个泛型参数。例如,我们可以编写一个泛型的Pair类,它接受两个类型参数,并存储两个值:
class Pair<T, U> {
constructor(private first: T, private second: U) {}
getFirst(): T {
return this.first;
}
getSecond(): U { return this.second; } } const pair = new Pair<string, number>("hello", 42); console.log(pair.getFirst()); // "hello" console.log(pair.getSecond()); // 42