TypeScript 2.0 是一个相当古老的版本(发布于 2025 年),自那时起,TypeScript 经历了多次重大更新(2.1, 2.4, 2.8, 3.0, 4.0, 5.0...),引入了大量新特性,如 unknown 类型、const 断言、可选链、空值合并、模板字面量类型等。

这份教程将分为两部分:
- 第一部分:TypeScript 2.0 核心概念,这部分内容是后续所有版本的基础,即使您现在学习最新版,这些知识也完全适用,我会重点介绍 2.0 版本引入和巩固的关键特性。
- 第二部分:从 2.0 到现代 TypeScript 的关键演进,这部分会简要介绍 2.0 之后出现的一些里程碑式特性,帮助您理解为什么现代 TypeScript 如此强大。
第一部分:TypeScript 2.0 核心概念
TypeScript 2.0 的主要目标是增强类型系统的安全性和易用性,它引入了两个非常核心的特性:strictNullChecks 和 --strict 模式,以及更强大的 non-null assertion 操作符。
环境搭建
在开始之前,请确保您的环境已准备好。
- 安装 Node.js: 从 nodejs.org 下载并安装 LTS 版本。
- 安装 TypeScript: 打开终端,运行以下命令全局安装 TypeScript。
npm install -g typescript
- 验证安装: 检查版本。
tsc --version
您应该会看到类似
Version 5.0.0或更高的版本,这没关系,因为tsc编译器向后兼容旧的语法。
(图片来源网络,侵删)
strictNullChecks (严格空检查)
这是 TypeScript 2.0 最重要的特性之一,在 2.0 之前,null 和 undefined 可以被赋值给任何类型的变量,这常常导致运行时错误(著名的“Cannot read property 'x' of null”错误)。
开启 strictNullChecks:
在 tsconfig.json 文件中设置:
{
"compilerOptions": {
"strictNullChecks": true
}
}
或者在命令行编译时加上 --strictNullChecks 标志。
示例:

不开启 strictNullChecks (旧版行为)
// 在 tsconfig.json 中设置 "strictNullChecks": false (这是默认值) let name: string = "Alice"; name = null; // 编译器不会报错! console.log(name.toUpperCase()); // 运行时错误: Cannot read property 'toUpperCase' of null
开启 strictNullChecks (2.0+ 行为)
// 在 tsconfig.json 中设置 "strictNullChecks": true
let name: string = "Alice";
name = null; // 编译时报错: Type 'null' is not assignable to type 'string'.
// 正确的做法是使用联合类型
let maybeName: string | null = "Bob";
maybeName = null; // OK
// 在使用前,必须检查是否为 null
if (maybeName) {
console.log(maybeName.toUpperCase()); // OK, 在这个分支里 TypeScript 知道 maybeName 不是 null
} else {
console.log("Name is null");
}
小结:strictNullChecks 强迫你显式处理 null 和 undefined,从而在编译阶段就消灭了大量潜在的空指针异常。
--strict 模式
--strict 是一个“总开关”,它会同时开启一系列最严格的编译选项,包括 strictNullChecks,对于新项目,强烈建议始终开启这个模式。
{
"compilerOptions": {
"strict": true
}
}
non-null assertion 操作符 ()
当你作为开发者,比编译器更确定一个值不会为 null 或 undefined 时,可以使用这个操作符来告诉编译器“相信我,这里没问题”。
它的语法是在变量或属性名后面加上一个感叹号 。
示例:
// 假设我们有一个从 DOM 获取元素的函数
const myElement = document.getElementById("my-button");
// myElement 的类型是 HTMLElement | null,因为元素可能不存在
// 错误用法:直接调用会报错,因为 myElement 可能为 null
// myElement.addEventListener('click', () => {}); // Error: Object is possibly 'null'.
// 解决方案 1: 使用类型守卫 (推荐)
if (myElement) {
myElement.addEventListener('click', () => {});
}
// 解决方案 2: 使用 non-null assertion (当你 100% 确保它存在时)
const myElement2 = document.getElementById("my-button")!; // 告诉 TS 它不可能是 null
myElement2.addEventListener('click', () => {}); // OK
警告:滥用 操作符会绕过 TypeScript 的类型检查,可能导致运行时错误,请只在您有绝对把握时使用它。
基础类型回顾
这是 TypeScript 的基石,在 2.0 中已经非常完善。
-
number: 用于所有数字,无论是整数还是浮点数。 -
string: 用于文本数据。 -
boolean: 用于true和false。 -
array: 两种定义方式:// 方式一: 在元素类型后面加上 [] let list: number[] = [1, 2, 3]; // 方式二: 使用泛型 Array<元素类型> let list2: Array<number> = [1, 2, 3];
-
tuple: 已知元素数量和类型的数组。// 定义一个包含 string 和 number 的元组 let x: [string, number]; x = ["hello", 10]; // OK // x = [10, "hello"]; // Error: Type 'number' is not assignable to type 'string'.
-
enum: 为一组数值赋予友好的名字。enum Color {Red, Green, Blue} let c: Color = Color.Green; -
any: 允许任何类型,在不得已的情况下使用(处理来自第三方库的动态数据)。 -
void: 表示没有任何类型,通常用作函数没有返回值时的返回类型。 -
null和undefined: 在strictNullChecks下,它们只能赋值给any和它们各自的类型(null只能赋给null,undefined只能赋给undefined)。
接口
接口是 TypeScript 的核心概念之一,用于定义对象的形状。
// 定义一个接口
interface User {
readonly id: number; // 只读属性
name: string;
age?: number; // 可选属性
}
// 实现接口
const user: User = {
id: 1,
name: "John Doe"
// age 是可选的,所以可以不提供
};
// user.id = 2; // Error: Cannot assign to 'id' because it is a read-only property.
函数
// 为函数的参数和返回值添加类型注解
function add(x: number, y: number): number {
return x + y;
}
// 箭头函数
const multiply = (x: number, y: number): number => {
return x * y;
};
// 函数类型定义
let myFunc: (x: number, y: number) => number;
myFunc = add; // OK
// myFunc = (a: string, b: string) => a + b; // Error
类
TypeScript 2.0 的类支持了 ES6 的大部分特性,并增加了类型系统。
interface Animal {
name: string;
makeSound(): void;
}
class Dog implements Animal { // implements 关键字表示类遵循一个接口
name: string;
// 构造函数
constructor(name: string) {
this.name = name;
}
// 方法
makeSound(): void {
console.log(`${this.name} says: Woof!`);
}
}
const myDog = new Dog("Rex");
myDog.makeSound(); // 输出: Rex says: Woof!
第二部分:从 2.0 到现代 TypeScript 的关键演进
了解 2.0 的基础后,了解一下后续版本的新特性会让你对 TypeScript 有更全面的认识。
| 特性 | 版本 | 简介 |
|---|---|---|
unknown 类型 |
0 | unknown 是 any 的类型安全版本,任何值都可以是 unknown,但必须先进行类型检查或类型断言才能使用它,有效防止了 any 带来的不安全性。 |
never 类型 |
0 | 0 正式完善了 never 类型,表示永不存在的值的类型,常用于函数抛出异常或无限循环,用于穷举类型检查。 |
| 类型推断增强 | 1+ | 推断能力越来越强,很多情况下可以省略显式类型注解,让代码更简洁。 |
object 类型 |
2 | 引入了新的 object 类型,用来表示非原始类型(即不是 string, number, symbol, boolean, bigint, null, undefined 的类型)。 |
readonly 修饰符 & readonly 数组 |
4 | 允许将属性或数组元素设置为只读,提供了比 interface 中的 readonly 更细粒度的控制。 |
keyof 操作符 |
1 | 获取某个类型所有键名的联合类型。keyof { a: number, b: string } 是 "a" \| "b"。 |
typeof 操作符 |
1 | 在类型上下文中获取一个变量或表达式的类型。typeof myVar 会得到 myVar 的类型。 |
Pick 和 Record 等实用工具类型 |
1 | 提供了一系列预定义的工具类型,用于从现有类型创建新类型,非常强大。 |
| 可选链 () | 7 | 简化深层嵌套对象属性的访问,如果中间某个属性为 null 或 undefined,表达式会短路并返回 undefined,而不会报错。 |
| 空值合并 () | 7 | 提供了一个比 更安全的空值检查。 只在左侧为 null 或 undefined 时返回右侧的值,而 在为“假值”(0, , false 等)时也会返回右侧的值。 |
const 断言 (as const) |
4 | 将一个值或对象的所有属性标记为 readonly,并将字面量类型推断为最窄的类型。 |
| 模板字面量类型 | 1 | 允许你通过模板字符串字面量来创建字符串类型,可以结合 keyof 和泛型实现强大的类型约束。 |
satisfies 操作符 |
9 | 一个非常新的操作符,它确保一个表达式满足某个类型,但不改变该表达式的原始推断类型。 |
总结与学习建议
- 打好基础是关键:TypeScript 2.0 引入的 严格模式 和 空检查 是现代 TypeScript 开发的基石,请务必深刻理解它们的工作原理。
- 从 2.0 开始,逐步进阶:您可以将这份教程作为起点,掌握了这些核心概念后,再逐步学习后续版本的新特性,官方的 TypeScript 手册 是最好的学习资源,它会按版本记录所有新特性。
- 实践出真知:不要只看不练,尝试用 TypeScript 重写一些你现有的 JavaScript 项目,或者创建一些小工具,在实践中遇到问题,然后去查资料解决,这是最高效的学习方式。
- 拥抱现代特性:一旦掌握了基础,请尽快学习和使用 可选链 ()、空值合并 () 和
unknown等现代特性,它们能极大地提升你的开发效率和代码质量。
