TypeScript何时应该使用类型注解

108 阅读2分钟

一、TypeScript 开发的注意事项

  1. 不要过度使用类型注解

    • TS 有强大的类型推断能力,无需为每个变量手动添加类型。
      // 无需显式类型(TS 自动推断为 string)
      const name = "John";
      
    • 仅在类型不明确或需要覆盖默认推断时使用注解。
  2. 优先使用接口(interface)还是类型别名(type)?

    • 接口:更适合定义对象结构,支持继承和自动合并(扩展)。

    • 类型别名:更灵活,可定义基本类型、联合类型等。

      interface User { name: string; }  // 接口
      type ID = string | number;        // 类型别名
      
  3. 避免使用 any

    • any 会绕过类型检查,失去 TS 的优势。尽量使用 unknown 代替,或明确类型。
  4. 使用严格模式(strict: true

    • 在 tsconfig.json 中启用严格模式,强制类型检查,减少潜在错误。
  5. 合理使用可选链(?.)和空值合并(??

    • 处理可能为 null 或 undefined 的值,避免运行时错误。

      const age = user?.age ?? 18;  // 如果 user.age 为 null/undefined,默认值为 18
      
  6. 理解类型守卫

    • 使用 typeofinstanceof 或自定义类型守卫缩小类型范围。

      function print(value: string | number) {
        if (typeof value === "string") {
          console.log(value.toUpperCase());  // TS 知道 value 是 string
        }
      }
      
  7. 模块化与命名空间

    • 使用 ES6 模块(import/export)而非命名空间(namespace),避免命名冲突。

二、何时需要使用类型注解?

  1. 函数参数和返回值

    • 明确函数的输入输出类型,提高代码可读性和安全性。
      function add(a: number, b: number): number {
        return a + b;
      }
      
  2. 变量类型不明确时

    • 当 TS 无法自动推断类型时(如初始化值为 null 或复杂类型)。

      let user: { name: string } | null = null;  // 初始值为 null,需显式类型
      
  3. 对象结构定义

    • 使用 interface 或 type 定义复杂对象的形状。
      interface Config {
        apiKey: string;
        timeout?: number;  // 可选属性
      }
      
  4. 联合类型和交叉类型

    • 处理多种可能的类型场景。

      type Response = Success | Error;  // 联合类型
      
  5. 泛型

    • 当组件或函数需要支持多种类型时(如数组、容器等)。

      function identity<T>(arg: T): T {
        return arg;
      }
      
  6. 类型断言(谨慎使用)

    • 当你比 TS 更了解某个值的类型时(如 DOM 操作)。

      const element = document.getElementById("app") as HTMLDivElement;
      
  7. 全局变量或第三方库适配

    • 为没有类型定义的库添加类型声明(如 declare 语句)。

总结

TypeScript 的核心优势在于静态类型检查,但应遵循 “够用就好” 的原则。优先依赖类型推断,在关键位置(如公共 API、复杂逻辑)显式使用类型注解,以平衡安全性和开发效率。