深入理解 JS TypeScript 泛型
在 JavaScript 编程中,TypeScript 为我们带来了强大的类型系统,而泛型则是其中一个非常重要的特性。它允许我们编写灵活且可复用的代码,在不同的数据类型上保持类型安全。
泛型的基本概念
泛型就像是一个“类型的占位符”。例如,我们定义一个函数,它可以接收不同类型的参数并返回相同类型的结果。在没有泛型时,我们可能会使用 any 类型,但这会失去类型检查的优势。而使用泛型,我们可以这样写:
function identity<T>(arg: T): T {
return arg;
}
这里的 <T> 就是泛型类型参数。T 可以代表任何类型,当我们调用 identity 函数时,TypeScript 会根据传入的参数类型自动推断 T 的具体类型。比如:
let num = identity<number>(5); // T 被推断为 number
let str = identity('hello'); // T 被推断为 string
泛型在接口中的应用
我们也可以在接口中使用泛型。假设我们有一个表示数据存储的接口:
interface DataStore<T> {
data: T;
setData(data: T): void;
getData(): T;
}
然后我们可以创建不同类型的 DataStore 实例:
class NumberStore implements DataStore<number> {
constructor(public data: number) {}
setData(data: number): void {
this.data = data;
}
getData(): number {
return this.data;
}
}
class StringStore implements DataStore<string> {
constructor(public data: string) {}
setData(data: string): void {
this.data = data;
}
getData(): string {
return this.data;
}
}
泛型约束
有时候,我们希望泛型类型满足一定的条件,这就需要用到泛型约束。比如,我们希望传入的类型有一个 length 属性(像字符串、数组等):
interface Lengthwise {
length: number;
}
function getLength<T extends Lengthwise>(arg: T): number {
return arg.length;
}
let strLength = getLength('test'); // 正确,字符串有 length 属性
// let numLength = getLength(5); // 错误,数字没有 length 属性
泛型类
除了函数和接口,类也可以是泛型的。例如一个简单的栈类:
class Stack<T> {
private items: T[] = [];
push(item: T): void {
this.items.push(item);
}
pop(): T | undefined {
return this.items.pop();
}
}
let numberStack = new Stack<number>();
numberStack.push(10);
let poppedNum = numberStack.pop();
let stringStack = new Stack<string>();
stringStack.push('one');
let poppedStr = stringStack.pop();
泛型与类型推断
TypeScript 强大的类型推断机制在泛型中也发挥着重要作用。很多时候,我们不需要显式地指定泛型类型参数,TypeScript 会根据上下文自动推断。比如:
function createArray<T>(...items: T[]): T[] {
return items;
}
let numArray = createArray(1, 2, 3); // 自动推断 T 为 number
let strArray = createArray('a', 'b'); // 自动推断 T 为 string
总结
JS TypeScript 泛型为我们提供了编写高度可复用、类型安全代码的能力。无论是在函数、接口、类还是其他场景中,合理运用泛型可以让我们的代码更加灵活和健壮。通过理解泛型的基本概念、约束以及与类型推断的配合,我们能够更好地利用 TypeScript 的优势,编写出高质量的 JavaScript 代码。随着项目规模的增大,泛型的价值会更加凸显,它帮助我们减少重复代码,提高代码的可维护性和可读性。

