MST

星途 面试题库

面试题:复杂场景下 TypeScript 上下文类型推导与类型兼容性

假设有一个函数 `combine<T extends { a: number }>(arr1: T[], arr2: T[]): T[]`,要求合并两个数组。现在有两个对象数组 `const arrA = [{ a: 1, b: 'test1' }, { a: 2, b: 'test2' }]` 和 `const arrB = [{ a: 3, c: 'test3' }]`,在使用 `combine` 函数时,TypeScript 的上下文类型推导会如何处理,会遇到什么类型兼容性问题,如何解决?
33.8万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试
  1. TypeScript上下文类型推导处理
    • 函数 combine 定义了类型参数 T 约束为具有 a 属性且类型为 number 的对象类型。
    • 当使用 combine(arrA, arrB) 时,TypeScript 会尝试根据 arrAarrB 的类型来推导 T 的具体类型。
    • arrA 的元素类型为 { a: number; b: string }arrB 的元素类型为 { a: number; c: string }。TypeScript 会寻找一个能同时兼容这两个数组元素类型的 T,它会取两者共有的属性 a,并将 T 推导为 { a: number }
  2. 类型兼容性问题
    • 因为 T 被推导为 { a: number },而 arrA 中的元素有额外的 b 属性,arrB 中的元素有额外的 c 属性。在合并后的数组中,这些额外属性可能会丢失。例如,如果函数内部只是简单地合并数组,返回的数组元素类型为 { a: number },像 arrA[0].b 这样的访问在类型检查时会报错,因为 { a: number } 类型没有 b 属性。
  3. 解决方法
    • 使用交叉类型
      • 可以定义一个新类型,它是 arrAarrB 元素类型的交叉类型。
      type CombinedType = { a: number } & ({ b: string } | { c: string });
      function combine<T extends CombinedType>(arr1: T[], arr2: T[]): T[] {
        return arr1.concat(arr2);
      }
      const arrA = [{ a: 1, b: 'test1' }, { a: 2, b: 'test2' }];
      const arrB = [{ a: 3, c: 'test3' }];
      const result = combine<CombinedType>(arrA, arrB);
      
    • 放宽类型约束
      • 如果可以接受丢失额外属性的情况,可以直接使用更宽泛的类型定义 combine 函数。
      function combine<T extends { a: number }>(arr1: T[], arr2: T[]): T[] {
        return arr1.concat(arr2);
      }
      const arrA = [{ a: 1, b: 'test1' }, { a: 2, b: 'test2' }] as { a: number }[];
      const arrB = [{ a: 3, c: 'test3' }] as { a: number }[];
      const result = combine(arrA, arrB);
      
      • 这里将 arrAarrB 类型断言为 { a: number }[],这样虽然丢失了额外属性的类型信息,但能满足 combine 函数的类型约束。不过这种方法可能会导致运行时访问不存在属性的错误,需要谨慎使用。