Skip to content

TypeScript

TypeScript 可以看成 在 JavaScript 之上增加静态类型系统和更强工程表达能力的一层扩展

它不是一门和 JavaScript 完全割裂的新语言,而是:

  1. 保留 JavaScript 的运行时模型
  2. 在开发阶段增加类型检查
  3. 帮助项目在规模变大后保持更好的可维护性

如果 JavaScript 更偏“这段代码运行时会发生什么”,那 TypeScript 更偏:

这段代码在写出来时,边界是否已经说清楚。

1. TypeScript 在解决什么问题

JavaScript 非常灵活,但项目一旦变大,灵活也会带来代价。

最常见的问题包括:

  1. 参数和返回值约束不清
  2. 对象结构变化后,调用方很晚才发现问题
  3. 重构成本越来越高
  4. IDE 补全和跳转能力不够稳定
  5. 多人协作时,接口约定越来越模糊

TypeScript 主要就是在解决这些问题。

说得直接一点,它不是在改变 JavaScript 的运行时,而是在开发阶段尽量提前发现问题。

2. 这部分会怎么拆

当前 TypeScript 目录先按四部分展开:

  1. 当前这篇目录页本身,负责建立类型系统和工程配置的基础认识
  2. 类型系统基础:interfacetypeenum 与泛型,负责把最常见的类型关键词和边界讲清楚
  3. 编译器、运行方式与工具生态,负责解释 tscts-nodetsxd.ts@types/* 以及常见工具链分工
  4. 装饰器:是什么、解决什么问题与实现示例,负责解释装饰器的定位、场景、示例和新旧写法差异

如果压缩成一句话,可以记成:第一部分讲 TypeScript 在约束什么,第二部分讲高频类型关键词到底在表达什么,第三部分讲 TypeScript 在工程里怎么被检查、转译和执行,第四部分讲框架场景里常见的装饰器。

3. 一条更适合理解 TypeScript 的主线

如果想系统一点地学 TypeScript,通常更适合按下面顺序理解:

  1. 先理解类型系统到底在约束什么
  2. 再理解 interfacetypeenum、联合类型这些表达能力
  3. 再进入类型推断、类型收窄、泛型这些核心机制
  4. 最后再看工程里的配置、边界和使用策略

如果顺序反过来,往往会出现:

  1. 会写泛型,但不知道泛型到底在解决什么问题
  2. 会写 interface,但不知道什么时候该用 type
  3. 会看到 unknownnever,但不知道它们为什么存在

4. TypeScript 的类型检查是怎么参与开发流程的

看一条很简化的流程:

mermaid
flowchart TD
    A[编写 TypeScript 代码] --> B[TypeScript 编译器检查类型]
    B --> C[发现不符合约束的问题]
    C --> D[修正代码或类型定义]
    D --> E[输出 JavaScript]
    E --> F[最终仍由 JavaScript 运行时执行]

这条图最值得先记住的是:TypeScript 主要在开发和编译阶段提供约束,而不是在运行时替 JavaScript 执行代码。

5. 抓住几类最核心的类型能力

如果把 TypeScript 的常见类型能力压缩来看,最值得先抓的是下面几类:

  1. 基础类型:例如 stringnumberboolean
  2. 对象类型:描述接口返回、组件 props、配置对象这类结构化数据
  3. 联合类型和字面量类型:表达“这个值可能是哪些情况”
  4. 类型收窄:让编译器根据条件判断逐步缩小类型范围
  5. 泛型:让逻辑复用时仍然保留类型信息
  6. 特殊类型:例如 anyunknownnever

例如:

ts
type Theme = 'light' | 'dark'

function first<T>(list: T[]): T | undefined {
  return list[0]
}

这里前者在表达“有限取值范围”,后者在表达“复用逻辑但不丢类型关系”。

工程上更常见的做法是:

  1. 让类型推断做该做的事
  2. 在函数边界、对象结构和复杂场景显式补充类型
  3. 少用 any,把 unknown、联合类型、类型守卫这些能力用起来

这些关键词如果展开讲,很容易把目录页讲得过深。所以更适合直接进入独立专题:

6. TypeScript 和 JavaScript 的关系

这两个目录的边界可以这样理解:

  1. JavaScript 更偏语言机制、执行机制和运行时
  2. TypeScript 更偏类型系统、约束表达和工程维护

也就是说:TypeScript 不是在替代 JavaScript,而是在帮助大型项目更稳地使用 JavaScript。

6.1 TypeScript 不是“更严格的 JavaScript 语法糖”

TypeScript 的价值,主要在于:

  1. 让函数边界更清楚
  2. 让对象结构更可验证
  3. 让重构更有把握
  4. 让 IDE 和编译器更懂你的代码

7. 工程里 tsconfig 到底在控制什么

很多 TypeScript 问题,不只来自代码写法,也来自配置策略。

tsconfig.json 常见会控制这些方向:

  1. 编译目标,例如 target
  2. 模块格式,例如 module
  3. 严格模式,例如 strict
  4. 路径别名,例如 paths
  5. 是否生成声明文件,例如 declaration

其中最值得优先关注的是:

  1. strict
  2. noImplicitAny
  3. strictNullChecks

因为这些选项直接决定:你的类型系统到底是“装饰性存在”,还是“真的在帮你发现问题”。

8. 工程上最容易踩的坑

8.1 把 TypeScript 当成“所有地方都要手写类型”

这会让代码显得冗长,而且没有必要。

8.2 大量使用 any

这样会让类型系统逐渐失去作用。

8.3 不区分 unknownany

会导致很多原本应该被约束的边界被直接放开。

8.4 泛型写得过度复杂

泛型应该服务复用和表达,不应该为了炫技把类型层层套得太深。

8.5 只会写类型,不会设计边界

TypeScript 真正的价值,不是“语法写得全”,而是:你能不能把模块、函数、组件和数据模型的边界表达清楚。

9. 一份更实用的检查清单

写 TypeScript 代码时,至少可以自查下面这些问题:

  1. 这个函数的参数和返回值是否清楚
  2. 这个对象结构是否应该抽成独立类型
  3. 当前场景该用 interface 还是 type
  4. 是否可以通过联合类型或字面量类型约束取值范围
  5. 是否应该用泛型保留类型信息
  6. 是否误用了 any
  7. tsconfig 的严格选项是否真的开启

10. 小结

如果把 TypeScript 压缩成一句话,可以记住:TypeScript 的核心价值,是在不改变 JavaScript 运行方式的前提下,把很多原本只能在运行时暴露的问题,提前到开发阶段发现。

如果继续往下读,比较自然的下一步有两条:

  1. 先进入 类型系统基础:interfacetypeenum 与泛型,把最常见的类型关键词边界先建立起来
  2. 再看 编译器、运行方式与工具生态,把 tscts-nodetsx、声明文件和构建工具链这条工程主线接起来
  3. 再看 装饰器:是什么、解决什么问题与实现示例,理解 TypeScript 在框架和声明式增强场景里的另一条常见主线

基于 VitePress 构建的个人技术笔记。