面试题答案
一键面试泛型约束概念
在TypeScript中,泛型约束用于限制泛型类型变量必须满足某些条件。通过泛型约束,可以确保在使用泛型时,传入的类型具有特定的结构或行为,从而避免运行时错误,并提供更准确的类型检查。
常见应用场景及示例
- 限制对象属性:
假设我们有一个函数,它接受一个对象和一个属性名,并返回该对象对应属性的值。我们希望确保传入的对象至少有指定的属性。
在这个例子中,function getProperty<T, K extends keyof T>(obj: T, key: K) { return obj[key]; } const person = { name: 'Alice', age: 30 }; const name = getProperty(person, 'name');// 正确 // const invalid = getProperty(person, 'unknown'); // 错误,'unknown' 不是 'person' 的属性
K extends keyof T
就是泛型约束。它确保K
是T
对象的属性名之一。这样可以提高代码的类型安全性,避免访问不存在的属性。 - 限制类型继承关系:
假设有一个函数,它接受两个对象,并将第一个对象的属性合并到第二个对象上。我们希望确保传入的两个对象类型是相关的,比如第二个对象是第一个对象的子类型。
这里class Animal { name: string; constructor(name: string) { this.name = name; } } class Dog extends Animal { breed: string; constructor(name: string, breed: string) { super(name); this.breed = breed; } } function merge<T extends U, U>(source: T, target: U): U { for (const key in source) { if (source.hasOwnProperty(key)) { target[key] = source[key] as any; } } return target; } const animal = new Animal('Tom'); const dog = new Dog('Jerry', 'Poodle'); const mergedDog = merge(animal, dog);
T extends U
确保了source
的类型T
是target
的类型U
的子类型,这样在合并属性时更安全,提高了类型安全性。同时,该函数可以复用在不同类型但有继承关系的对象上,提高了复用性。 - 限制函数参数类型:
假设有一个函数,它接受一个数组和一个函数,然后对数组中的每个元素应用该函数。我们希望确保传入的函数接受数组元素类型作为参数。
这里function mapArray<T, U>(arr: T[], callback: (item: T) => U): U[] { return arr.map(callback); } const numbers = [1, 2, 3]; const squaredNumbers = mapArray(numbers, (num) => num * num);
(item: T) => U
对callback
函数的参数类型进行了约束,确保callback
函数能够正确处理T
类型的数组元素,提高了类型安全性,并且该mapArray
函数可以复用在不同类型的数组上,提高了复用性。
提高类型安全性和复用性
- 类型安全性:泛型约束通过明确类型之间的关系,使得TypeScript编译器能够在编译时捕获更多类型错误。比如在访问对象属性的例子中,避免了访问不存在属性导致的运行时错误。
- 复用性:通过使用泛型约束,我们可以编写适用于多种类型但又满足特定条件的代码。例如上述
mapArray
函数可以处理不同类型的数组,只要传入的回调函数符合对数组元素类型的约束即可,从而减少了重复代码的编写。