MST

星途 面试题库

面试题:TypeScript中的泛型约束及应用场景

解释TypeScript中泛型约束的概念,并举例说明在实际项目开发中,泛型约束常见的应用场景有哪些,以及如何通过泛型约束提高代码的类型安全性和复用性。
49.5万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

泛型约束概念

在TypeScript中,泛型约束用于限制泛型类型变量必须满足某些条件。通过泛型约束,可以确保在使用泛型时,传入的类型具有特定的结构或行为,从而避免运行时错误,并提供更准确的类型检查。

常见应用场景及示例

  1. 限制对象属性: 假设我们有一个函数,它接受一个对象和一个属性名,并返回该对象对应属性的值。我们希望确保传入的对象至少有指定的属性。
    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 就是泛型约束。它确保 KT 对象的属性名之一。这样可以提高代码的类型安全性,避免访问不存在的属性。
  2. 限制类型继承关系: 假设有一个函数,它接受两个对象,并将第一个对象的属性合并到第二个对象上。我们希望确保传入的两个对象类型是相关的,比如第二个对象是第一个对象的子类型。
    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 的类型 Ttarget 的类型 U 的子类型,这样在合并属性时更安全,提高了类型安全性。同时,该函数可以复用在不同类型但有继承关系的对象上,提高了复用性。
  3. 限制函数参数类型: 假设有一个函数,它接受一个数组和一个函数,然后对数组中的每个元素应用该函数。我们希望确保传入的函数接受数组元素类型作为参数。
    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) => Ucallback 函数的参数类型进行了约束,确保 callback 函数能够正确处理 T 类型的数组元素,提高了类型安全性,并且该 mapArray 函数可以复用在不同类型的数组上,提高了复用性。

提高类型安全性和复用性

  • 类型安全性:泛型约束通过明确类型之间的关系,使得TypeScript编译器能够在编译时捕获更多类型错误。比如在访问对象属性的例子中,避免了访问不存在属性导致的运行时错误。
  • 复用性:通过使用泛型约束,我们可以编写适用于多种类型但又满足特定条件的代码。例如上述 mapArray 函数可以处理不同类型的数组,只要传入的回调函数符合对数组元素类型的约束即可,从而减少了重复代码的编写。