MST
星途 面试题库

面试题:TypeScript结构类型的类型兼容性

在TypeScript中,假设存在两个接口`InterfaceA`和`InterfaceB`,`InterfaceA`有属性`a`(字符串类型)和`b`(数字类型),`InterfaceB`有属性`a`(字符串类型)、`b`(数字类型)和`c`(布尔类型)。请解释为什么一个类型为`InterfaceB`的对象可以赋值给类型为`InterfaceA`的变量,同时说明这种结构类型兼容性在实际项目中的利弊,并举例说明如何避免因这种兼容性可能导致的潜在问题。
33.1万 热度难度
前端开发TypeScript

知识考点

AI 面试

面试题答案

一键面试
  1. 赋值原因
    • 在TypeScript中,接口遵循结构类型系统。InterfaceB包含了InterfaceA的所有属性(ab,且类型相同),因此从结构上看,InterfaceB类型的对象满足InterfaceA的结构要求,所以可以赋值给InterfaceA类型的变量。
  2. 利弊分析
      • 灵活性:这种兼容性使得代码更加灵活。例如,在函数参数类型定义中,如果函数接受InterfaceA类型的参数,那么实际上也可以传入InterfaceB类型的对象,这样在不修改函数定义的情况下,可以接受更多符合一定结构的对象,减少了重复代码。
      • 扩展性:有利于代码的扩展。当需要在原有的接口基础上添加新属性时,只要新接口包含旧接口的所有属性,就可以继续使用原来依赖旧接口的代码,而无需大量修改。
      • 潜在的类型错误:由于InterfaceB类型对象赋值给InterfaceA类型变量后,在使用该变量时,TypeScript编译器不会检查InterfaceB特有的属性(如c),如果代码中意外地访问了c属性,可能会导致运行时错误。
      • 可读性降低:从代码阅读角度,可能会让阅读者困惑为什么一个可能包含更多属性的对象能赋值给一个看起来属性更少的类型变量,增加了理解代码的难度。
  3. 避免潜在问题的示例
    • 类型断言
      interface InterfaceA {
        a: string;
        b: number;
      }
      interface InterfaceB {
        a: string;
        b: number;
        c: boolean;
      }
      const objB: InterfaceB = { a: 'test', b: 1, c: true };
      const objA: InterfaceA = objB;
      // 如果需要访问c属性,可以先进行类型断言
      if ((objA as InterfaceB).c) {
        console.log('c is true');
      }
      
    • 使用类型守卫
      function isInterfaceB(obj: InterfaceA | InterfaceB): obj is InterfaceB {
        return (obj as InterfaceB).c!== undefined;
      }
      const objB: InterfaceB = { a: 'test', b: 1, c: true };
      const objA: InterfaceA = objB;
      if (isInterfaceB(objA)) {
        console.log(objA.c);
      }