今天在 GitHub Trending 上看到一个有意思的项目:TypeScript(microsoft/TypeScript)。作为当今前端与全栈开发的基石,TypeScript 为 JavaScript 这门前无类型的脚本语言叠加了可选的静态类型系统,让大型应用也能保持可维护性与可演进性。

一、项目概述

TypeScript 是微软开源的一门语言,官方定义是「a language for application-scale JavaScript development」——为应用级规模的 JavaScript 开发而生。它本质上是 JavaScript 的一个超集(superset):任何合法的 JS 代码都是合法的 TS 代码,在此之上增加了一套可选的静态类型系统。

它主要解决三类痛点:

  • 可维护性:在数十万行代码、多人协作的项目中,类型即文档,重构时编译器能替你把住关。
  • 错误前移:大量 undefined is not a function 这类运行时错误,在编译期就能被捕获。
  • 开发体验:基于类型信息的自动补全、跳转定义、重命名重构,是 IDE 智能提示的基础。

其核心特性包括:类型推断、联合类型(union types)、泛型、类型收窄(narrowing)、装饰器、以及描述外部库形状的 .d.ts 声明文件。值得一提的是,TypeScript 的编译产物是可读的、符合标准的 JavaScript,而非某种私有字节码,因此可以运行在任何浏览器、任何宿主、任何操作系统上。

当前仓库 package.json 中稳定版本为 6.0.0,而代号 TypeScript 7.0(向 Go 语言原生移植的版本,社区常称 “Native Port”)正在推进中——这也是本文后面要重点聊的演进方向。

二、技术原理

2.1 三大构建产物

从 Herebyfile.mjs 的构建定义可以看出,TypeScript 自身被拆成三个互相依赖的输出单元,全部由 hereby 任务运行器编排、esbuild 打包:

  • tsc:命令行编译器(src/tsc),入口 ./src/tsc/tsc.ts,最终产出 built/local/tsc.js。
  • services:核心类型库 typescript.js(src/typescript),是几乎所有生态工具(babel、eslint、webpack 等)消费的内核。
  • tsserver:语言服务服务器(src/tsserver),为编辑器提供补全、诊断、跳转、重构等能力。

例如构建 typescript.js 库的打包配置片段:

const { main: services, build: buildServices } = entrypointBuildTask({
    name: "services",
    description: "Builds the typescript.js library",
    buildDeps: [generateDiagnostics],
    project: "src/typescript",
    srcEntrypoint: "./src/typescript/typescript.ts",
    builtEntrypoint: "./built/local/typescript/typescript.js",
    output: "./built/local/typescript.js",
    mainDeps: [generateLibs],
    bundlerOptions: { exportIsTsObject: true },
});

而 createBundler 内部使用的 esbuild 选项,揭示了对运行环境的取舍——目标锁定 es2020 与 node14.17,以 CommonJS 格式打包,并把第三方包标记为 external:

const options = {
    entryPoints: [entrypoint],
    bundle: true,
    outfile,
    platform: "node",
    target: ["es2020", "node14.17"],
    format: "cjs",
    sourcemap: "linked",
    packages: "external",
    logLevel: "warning",
};

2.2 结构化类型与类型擦除

TypeScript 的类型系统是结构化(structural)而非名义(nominal)的——两个类型只要「形状」一致即兼容,这正是鸭子类型思想的静态化。更关键的是,类型信息在编译后会被完全擦除(type erasure):运行时不存在任何类型对象,因此 TS 不会带来运行时性能开销。这也意味着 interface 和 type 在运行时「什么都不做」,只活在编译期。

2.3 7.0 原生移植(typescript-go)

README 的「Contribute」一节透露了一个重大信号:当前 microsoft/TypeScript 仓库的代码变更已被严格限制——仅接受「在 5.9 或 6.0 引入、且在 7.0 仍能复现的崩溃」「安全问题」「语言服务崩溃」「5.9 的严重回归」这四类修复;绝大多数 bug fix 应提交到 microsoft/TypeScript-go 仓库;功能新增与行为变更在 7.0 完成前处于冻结状态。

换言之,TypeScript 正在用 Go 重写编译器内核(代号 “native”),目标是大幅缩短编译与语言服务响应时间。7.0 完成后,类型系统的能力与 JS 输出保持不变,变化的是底层实现语言。

三、安装与快速开始

安装稳定版(开发依赖即可,因为 tsc 只参与构建):

npm install -D typescript

如需试用尚未发布的功能,可安装每日构建的 nightly:

npm install -D typescript@next

初始化项目并编译:

npx tsc --init   # 生成 tsconfig.json
npx tsc          # 按 tsconfig 编译

环境要求:node >= 14.17(仓库 volta 推荐 node 22.22.0)。一个最小可运行示例:

// greet.ts
function greet(name: string): string {
  return `Hello, ${name}!`;
}

const msg: string = greet("TypeScript");
console.log(msg);

执行 npx tsc greet.ts 会产出对应的 greet.js,用 node greet.js 即可运行。

四、使用方法与实战

4.1 编译与监听

npx tsc                  # 单次编译
npx tsc --watch          # 监听模式,文件变更自动重编译
npx tsc --build          # 配合 project references 做增量构建

4.2 类型收窄实战

TypeScript 会在控制流中自动收窄联合类型,从而获得精确的补全:

function format(value: string | number): string {
  if (typeof value === "number") {
    return value.toFixed(2);   // 此处 value 被收窄为 number
  }
  return value.toUpperCase();  // 此处 value 仍是 string
}

4.3 泛型与编辑器集成

tsserver 是编辑器智能提示的引擎。在 VS Code 等编辑器中打开 .ts 文件时,背后正是一个 tsserver 进程在持续提供诊断与补全。得益于 services 导出的 typescript.js 库,社区工具链(ESLint、Babel、JSDoc 等)才能直接复用同一套类型 API。

五、常见问题与解决方案

  • 安装报 node 版本过低:TypeScript 要求 node >= 14.17,建议使用 volta 或 nvm 切到较新 LTS(仓库推荐 Node 22)。
  • 「类型 X 上不存在属性 Y」:通常是类型推断不够精确或缺少 .d.ts 声明。检查是否遗漏类型导入,或在 tsconfig.json 中开启 strict 以获得更准确的报错定位。
  • implicit any 报错:在严格模式下未标注类型的参数会报 noImplicitAny。可显式标注类型,或在非严格子项目里通过 noImplicitAny: false 关闭(不推荐长期使用)。
  • 编译/类型检查太慢:开启增量编译(tsc --incremental 或 tsconfig 中 incremental: true)、拆分 project references、缩小 include 范围,避免每次全量分析。
  • 想参与贡献却不知道往哪提:请注意当前主仓库(TypeScript)已冻结功能开发,bug fix 与功能应提交到 microsoft/TypeScript-go(7.0 原生移植版),主仓库仅收特定类别的修复。

六、总结

TypeScript 用「可选类型 + 类型擦除 + 结构化类型」的组合,在几乎零运行时成本的前提下,把 JavaScript 从脚本语言抬升到了可支撑大型应用的工业级语言。它自身的工程也相当讲究——hereby + esbuild 的构建体系、tsc/services/tsserver 的清晰分层,以及正在推进的 7.0 Go 原生移植(typescript-go),都说明这门语言仍在持续进化。对于今天的 Web 与全栈开发者而言,理解 TypeScript 的编译原理与类型机制,依旧是提升工程质量的必修课。

仓库地址:https://github.com/microsoft/TypeScript