讲解

类型标注(type annotation)是用冒号语法显式声明一个绑定(变量、参数、返回值)的类型,例如 let name: string。它像一份契约:之后所有对这个绑定的读写都必须遵守契约,否则编译器立刻报错。

但 TypeScript 并不要求你处处标注,因为它有强大的类型推断(type inference)能力。let name = "小林" 没有标注,编译器依然知道 name 是 string——它从初始化值推断了类型。之后再写 name = 42 照样报错。TypeScript 官方风格指南的建议是:能推断就不标注,把标注留给推断不出来或需要明确契约的地方。

哪些地方值得显式标注?一是函数参数——参数没有初始化值,无法推断,必须标注;二是函数返回值——虽然能推断,但标注可以让函数实现内部的错误更早暴露(否则错误要等到调用点才出现);三是没有初始值的变量(let x: string; 稍后赋值);四是推断结果过宽或过窄、不符合你意图的场景,比如字面量会被推断为具体值类型还是宽类型,后续章节会细讲。

示例

标注与推断的对照:下面四个变量中,只有 first 显式标注了,其余全靠推断,但类型同样精确:

let first: string = "显式标注";
let second = "推断为 string";
let third = 42; // 推断为 number
let fourth = [1, 2, 3]; // 推断为 number[]

// second = 100; // 若取消注释:number 不能赋给 string
console.log(first, second, third, fourth.length);

函数参数的标注是强制的(在 noImplicitAny 下),返回值标注推荐显式写出:

function repeat(text: string, times: number): string {
  return text.repeat(times);
}

const slogan: string = repeat("类型安全 ", 3);
console.log(slogan);

一个没有初始值的变量必须标注,否则会被推断为 any 的隐式形态而失去保护:

let score: number;
score = 95;
// score = "优秀"; // 若取消注释:string 不能赋给 number
console.log(`得分:${score}`);

常见坑

  • 过度标注:写 let x: number = 1 属于噪音,推断已经给出同样结果;标注越多不代表越专业。
  • 不标函数返回值:实现里 return 错类型时,错误会漂移到调用点,排查路径变长。公共函数务必标注返回值。
  • 误以为推断是「弱类型」:推断出的类型和手写的一样严格,该报的错一个不少。
  • 改了实现忘了改标注:显式标注过多时,重构会产生大量无效修改,这也是「能推断就不标注」的现实理由。

小结

类型标注用冒号语法声明契约;类型推断让大多数标注成为多余。原则:参数必须标、返回值推荐标、变量能推断就不标。下一章系统认识 TypeScript 的基本类型。