TS 类型断言(上)

5,165 阅读2分钟

定义:类型断言(Type Assertion)可以用来手动指定一个值的类型。

为了更好的兼容,建议大家在使用类型断言时,统一使用 值 as 类型 这样的语法。

  • 类型断言的用途

    • 将一个联合类型断言为其中一个类型。

      当 TypeScript 不确定一个联合类型的变量到底是哪个类型的时候,我们只能访问此联合类型的所有类型中共有的属性或方法,而有时候,我们确实需要在还不确定类型的时候就访问其中一个类型特有的属性或方法.我们采用断言将其指定为一个类型。(这么做只是“欺骗了”ts,让其信任我们所指定的类型)

      interface Cat {
          name: string;
          run(): void;
      }
      interface Fish {
          name: string;
          swim(): void;
      }
      
      function isFish(animal: Cat | Fish) {
          if (typeof (animal as Fish).swim === 'function') {
              return true;
          }
          return false;
      }
      
      // 乱使用类型断言虽然在编译期间无问题,运行时依然报错
      interface Cat {
          name: string;
          run(): void;
      }
      interface Fish {
          name: string;
          swim(): void;
      }
      
      function swim(animal: Cat | Fish) {
          (animal as Fish).swim();
      }
      
      const tom: Cat = {
          name: 'Tom',
          run() { console.log('run') }
      };
      swim(tom);
      // Uncaught TypeError: animal.swim is not a function`
      
    • 将一个父类断言为更加具体的子类

      class ApiError extends Error {
          code: number = 0;
      }
      class HttpError extends Error {
          statusCode: number = 200;
      }
      // 使用该函数判断错误类型是何
      // 它的参数的类型是比较抽象的父类 Error,这样的话这个函数就能接受 Error 或它的子类作为参数了
      //但是由于父类 Error 中没有 code 属性,会报错,需要使用类型断言获取 (error as ApiError).code
      function isApiError(error: Error) {
            if (typeof (error as ApiError).code === 'number') {
              return true;
          }
          return false;
      }
      

    实话说肯定是instanceof更为合适去判断子类父类的。但是有时候 ApiError 和 HttpError 不是一个真正的类,而只是一个 接口(interface),不是一个真正的值,它在编译成js后会被删除,无法使用 instanceof 来做判断了:

      interface ApiError extends Error {
          code: number;
      }
      interface HttpError extends Error {
          statusCode: number;
      }
      
      function isApiError(error: Error) {
          if (error instanceof ApiError) {
              return true;
          }
          return false;
      }
    
    • 将任何一个类型断言为 any

    window.foo = 1; // 我们非常确定这段代码不会出错,但ts编译时还是会报错
    // 改写
    (window as any).foo = 1;
    

    此功能不能滥用。但是可以使用。

    • 将 any 断言为一个具体的类型

    可能时历史的原因,也可能时以前那位编写库的程序员水平不足,使得库内的一些函数返回值为any。如果不管理他,类型推断会使得产生更多的any,我们适当的在使用的时候令其断言为具体的类型而不是任由其发展。 在我们使用的时候将其断言为一个具体的类型

    function getCacheData(key: string): any {
        return (window as any).cache[key];
    }
    
    interface Cat {
        name: string;
        run(): void;
    }
    
    const tom = getCacheData('tom') as Cat;
    tom.run()