MST

星途 面试题库

面试题:TypeScript类型系统对代码生成的约束及突破

已知一个复杂的TypeScript类型定义,例如一个嵌套的联合类型与交叉类型组合的类型。描述在基于此类型进行代码生成时,类型系统会施加哪些约束,并且举例说明如何在遵循类型安全的前提下,突破部分约束以实现特定的代码生成需求。
18.9万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试

类型系统施加的约束

  1. 赋值兼容性:当基于复杂类型进行代码生成时,赋值操作必须满足类型兼容性规则。例如,在联合类型 A | B 中,赋值给该联合类型变量的值必须是 A 类型或 B 类型。
    type Fruit = 'apple' | 'banana';
    let myFruit: Fruit;
    myFruit = 'apple'; // 正确
    myFruit = 'cherry'; // 错误,'cherry' 不在联合类型中
    
  2. 属性访问:对于交叉类型 A & B,访问属性时必须确保该属性同时存在于 AB 类型中。
    type User = { name: string };
    type Admin = { role: string };
    type UserAdmin = User & Admin;
    let userAdmin: UserAdmin;
    userAdmin.name; // 正确
    userAdmin.role; // 正确
    userAdmin.age; // 错误,User 和 Admin 类型都没有 'age' 属性
    
  3. 函数参数和返回值:如果基于复杂类型定义函数参数或返回值,调用函数时传入的参数必须符合参数类型,返回值必须符合返回类型。
    type NumOrStr = number | string;
    function printValue(value: NumOrStr): void {
        if (typeof value === 'number') {
            console.log(value.toFixed(2));
        } else {
            console.log(value.toUpperCase());
        }
    }
    printValue(123); // 正确
    printValue('abc'); // 正确
    printValue(true); // 错误,boolean 类型不符合 NumOrStr 类型
    

突破部分约束以实现特定代码生成需求

  1. 类型断言:通过类型断言,可以告诉编译器某个值的类型,从而突破部分类型约束。但需谨慎使用,因为如果断言错误,可能导致运行时错误。
    type Shape = { kind: 'circle' |'square' };
    type Circle = Shape & { kind: 'circle'; radius: number };
    type Square = Shape & { kind:'square'; sideLength: number };
    let shape: Shape = { kind: 'circle' };
    let circle = shape as Circle; // 假设已知 shape 实际是 Circle 类型
    console.log(circle.radius); // 这里如果 shape 实际不是 Circle 类型会出错
    
  2. 类型守卫:使用类型守卫可以在运行时检查值的类型,从而在遵循类型安全的前提下,针对不同类型执行特定代码生成逻辑。
    type Animal = { type: 'dog' | 'cat' };
    type Dog = Animal & { type: 'dog'; bark: () => void };
    type Cat = Animal & { type: 'cat'; meow: () => void };
    function handleAnimal(animal: Animal) {
        if (animal.type === 'dog') {
            const dog = animal as Dog;
            dog.bark();
        } else {
            const cat = animal as Cat;
            cat.meow();
        }
    }
    
  3. 索引类型查询和映射类型:在处理对象类型时,索引类型查询和映射类型可以动态生成新类型,从而满足特定代码生成需求。
    type UserInfo = { name: string; age: number };
    type UserInfoKeys = keyof UserInfo; // 'name' | 'age'
    type ReadonlyUserInfo = { readonly [K in UserInfoKeys]: UserInfo[K] };
    let readonlyUser: ReadonlyUserInfo = { name: 'John', age: 30 };
    // readonlyUser.name = 'Jane'; // 错误,ReadonlyUserInfo 类型的属性是只读的