TypeScript 是什么?为什么要用它

本节目标

TypeScript 是 JavaScript 的超集(superset):任何合法的 JS 代码,都是合法的 TS 代码。它在 JS 之上加了一层静态类型系统,最终会被编译(更准确说是「转译」)回纯 JS 再运行。

TS 源码(带类型标注)  --tsc / 构建工具-->  纯 JS  --Node / 浏览器-->  运行

类型系统主要帮我们解决三类痛点:

  1. 把低级错误挡在写代码阶段:属性名拼错、给函数传了错误类型的参数,IDE 立刻标红,而不是等上线后用户报错。
  2. 工具链体验质变:智能提示、自动补全、跳转定义、安全重构,全部建立在类型信息之上。
  3. 代码即文档:函数签名直接表达「怎么用」,别人不用读函数体。

下面这段代码运行时其实什么都不会打印,但它演示了「类型检查在编译期发生」这件事:

// 运行环境:需要 TypeScript(任何版本)
// 运行 / 类型检查方式:把下面内容存为 ts-l1.ts,终端执行  npx tsc --noEmit ts-l1.ts
// 你会看到编译器报错:Argument of type 'string' is not assignable to parameter of type 'number'

// 给参数 a、b 标注了 number 类型
function sum(a: number, b: number): number {
  return a + b
}

// 故意传错类型:TS 在「写代码时」就拦住了,根本走不到运行
sum('1', '2')

关键认知:类型检查只发生在编译期,编译成 JS 后类型信息会被「擦除」。所以 TS 不会让程序变慢,但也意味着运行时出现的数据结构错误 TS 管不了(比如接口返回的数据字段变了)。这一点是很多初学者栽跟头的地方。

名词解释

类型(Type):对「这个值能是什么、能做什么」的一种描述。比如 number 类型表示「这是一个数字,可以做加减乘除」;string 表示「这是一段文字」。你可以把类型理解成给变量贴的「标签」,编译器靠这个标签判断你有没有用错。

静态类型检查(Static Type Checking):在代码还没运行的时候(写代码或编译时)就检查类型是否正确。对比「动态类型」语言(如纯 JS)要等运行时才可能报错,静态检查相当于「提前考试」,把 bug 挡在出厂前。

课后练习

练习 1:为什么说「TypeScript 是 JavaScript 的超集」?请举一个「合法 JS 但不依赖任何 TS 特性」的例子。

答案:因为 TS 完全兼容 JS 语法。例如 const x = 1; console.log(x) 既是合法 JS,也是合法 TS——它不写任何类型标注也能通过 TS 编译。所谓「超集」就是:JS 的所有语法 TS 都认,TS 只是额外多了一套类型语法。

练习 2:下面哪类错误 TS 能在编译期发现,哪类不能?
(a)调用 user.name 但 user 其实是 null;
(b)把 fetch 返回的 JSON 当成了你期望的 { id: number } 结构,但其实接口返回了 { userId: number }。

答案:(a)如果你给 user 标注了 User | null 类型,TS 会强制你先判空,能在编译期发现;(b)TS 管不了。fetch 拿到的是运行时才确定的网络数据,类型在编译期是「猜」的——如果标注写错,TS 不会报错,这是 TS 的已知边界。

总结

我认为初学者最容易误解的一点是:以为学会 TS 就是「多写几个 : type」。其实 TypeScript 真正的价值不在语法,而在它逼你和「数据的形状」较真。当你给每个变量、每个函数参数都认真想清楚「它到底是什么」,你写的代码从根上就更不容易出 bug。但请记住:TS 不是银弹。它只在编译期有用,运行时的脏数据(接口返回、用户输入)仍然要靠运行时校验(如 zod)兜底。所以我的建议是:把 TS 当「编译期的好搭档」,别把它当成「运行时安全的保证书」。