面向 JavaScript 程序员的 TypeScript

TypeScript 与 JavaScript 的关系非同寻常。TypeScript 提供了 JavaScript 的全部特性,并在其之上增加了一层:TypeScript 的类型系统。

例如,JavaScript 提供了 string 和 number 这样的语言原语,但它不会检查你是否始终一致地赋值这些类型。TypeScript 会。

这意味着,你现有可正常运行的 JavaScript 代码同时也是 TypeScript 代码。TypeScript 的主要好处在于,它能标出代码中出乎意料的行为,从而降低出现 bug 的几率。

本教程简要概述 TypeScript,重点介绍其类型系统。

通过推断得到的类型

TypeScript 了解 JavaScript 语言,在许多情况下会为你生成类型。例如,在创建变量并将其赋值为某个特定值时,TypeScript 会把该值用作它的类型。

ts
let helloWorld = "Hello World";
let helloWorld: string
Try

通过理解 JavaScript 的工作方式,TypeScript 可以构建一个既能接受 JavaScript 代码、又带有类型的类型系统。这提供了一种类型系统,无需在代码中添加额外字符来显式标注类型。正因如此,TypeScript 才能知道上例中的 helloWorld 是 string。

你可能在 Visual Studio Code 中编写过 JavaScript,并体验过编辑器自动补全。Visual Studio Code 在底层使用 TypeScript,让处理 JavaScript 更加轻松。

定义类型

在 JavaScript 中,你可以使用各种各样的设计模式。然而,某些设计模式会让类型难以被自动推断(例如使用动态编程的模式)。为了涵盖这些情况,TypeScript 支持 JavaScript 语言的一项扩展,它提供了让你告诉 TypeScript 类型应该是什么的地方。

例如,要创建一个推断类型包含 name: string 和 id: number 的对象,你可以这样写:

ts
const user = {
name: "Hayes",
id: 0,
};
Try

你可以使用 interface 声明来显式描述这个对象的形状:

ts
interface User {
name: string;
id: number;
}
Try

然后,你可以在变量声明之后使用类似 : TypeName 的语法,声明某个 JavaScript 对象符合这个新 interface 的形状:

ts
const user: User = {
name: "Hayes",
id: 0,
};
Try

如果你提供的对象与你提供的接口不匹配,TypeScript 会发出警告:

ts
interface User {
name: string;
id: number;
}
 
const user: User = {
username: "Hayes",
Object literal may only specify known properties, and 'username' does not exist in type 'User'.2353Object literal may only specify known properties, and 'username' does not exist in type 'User'.
id: 0,
};
Try

既然 JavaScript 支持类和面向对象编程,TypeScript 也同样支持。你可以将接口声明用于类:

ts
interface User {
name: string;
id: number;
}
 
class UserAccount {
name: string;
id: number;
 
constructor(name: string, id: number) {
this.name = name;
this.id = id;
}
}
 
const user: User = new UserAccount("Murphy", 1);
Try

你可以使用接口为函数的参数和返回值添加注解:

ts
function deleteUser(user: User) {
// ...
}
 
function getAdminUser(): User {
//...
}
Try

JavaScript 中已经有一小组可用的原始类型:boolean、bigint、null、number、string、symbol 和 undefined,你可以在接口中使用它们。TypeScript 在此列表之上又扩展了几个,例如 any(允许任何值)、unknown(确保使用该类型的人声明它是什么类型)、never(该类型不可能发生)以及 void(返回 undefined 或没有返回值的函数)。

你会看到,构建类型有两种语法:接口和类型。应优先使用 interface。当你需要特定功能时,再使用 type。

组合类型

在 TypeScript 中,你可以通过组合简单的类型来创建复杂类型。有两种常用的方式:联合类型和泛型。

联合类型

使用联合类型,你可以声明一个类型可能是多种类型之一。例如,你可以将 boolean 类型描述为 true 或 false:

ts
type MyBool = true | false;
Try

注意:如果你将鼠标悬停在上面的 MyBool 上,会看到它被归类为 boolean。这是结构化类型系统的一个特性。详见下文。

联合类型的一个常见用例是描述某个值允许取的 string 或 number字面量集合:

ts
type WindowStates = "open" | "closed" | "minimized";
type LockStates = "locked" | "unlocked";
type PositiveOddNumbersUnderTen = 1 | 3 | 5 | 7 | 9;
Try

联合类型也提供了一种处理不同类型的方式。例如,你可能有一个接受 array 或 string 的函数:

ts
function getLength(obj: string | string[]) {
return obj.length;
}
Try

要了解变量的类型,请使用 typeof:

类型 谓词
string typeof s === "string"
number typeof n === "number"
boolean typeof b === "boolean"
undefined typeof undefined === "undefined"
function typeof f === "function"
array Array.isArray(a)

例如,你可以让函数根据传入的是字符串还是数组返回不同的值:

ts
function wrapInArray(obj: string | string[]) {
if (typeof obj === "string") {
return [obj];
(parameter) obj: string
}
return obj;
}
Try

泛型

泛型为类型提供变量。一个常见的例子是数组。没有泛型的数组可以包含任何内容。带泛型的数组则可以描述数组所包含的值。

ts
type StringArray = Array<string>;
type NumberArray = Array<number>;
type ObjectWithNameArray = Array<{ name: string }>;

你可以声明自己使用泛型的类型:

ts
interface Backpack<Type> {
add: (obj: Type) => void;
get: () => Type;
}
 
// This line is a shortcut to tell TypeScript there is a
// constant called `backpack`, and to not worry about where it came from.
declare const backpack: Backpack<string>;
 
// object is a string, because we declared it above as the variable part of Backpack.
const object = backpack.get();
 
// Since the backpack variable is a string, you can't pass a number to the add function.
backpack.add(23);
Argument of type 'number' is not assignable to parameter of type 'string'.2345Argument of type 'number' is not assignable to parameter of type 'string'.
Try

结构化类型系统

TypeScript 的核心原则之一是:类型检查关注值所具有的形状。这有时被称为“鸭子类型”或“结构化类型”。

在结构化类型系统中,如果两个对象具有相同的形状,它们就被视为同一类型。

ts
interface Point {
x: number;
y: number;
}
 
function logPoint(p: Point) {
console.log(`${p.x}, ${p.y}`);
}
 
// logs "12, 26"
const point = { x: 12, y: 26 };
logPoint(point);
Try

point 变量从未被声明为 Point 类型。然而,TypeScript 在类型检查中会比较 point 的形状与 Point 的形状。它们的形状相同,因此代码通过了检查。

形状匹配只要求对象的部分字段匹配即可。

ts
const point3 = { x: 12, y: 26, z: 89 };
logPoint(point3); // logs "12, 26"
 
const rect = { x: 33, y: 3, width: 30, height: 80 };
logPoint(rect); // logs "33, 3"
 
const color = { hex: "#187ABF" };
logPoint(color);
Argument of type '{ hex: string; }' is not assignable to parameter of type 'Point'. Type '{ hex: string; }' is missing the following properties from type 'Point': x, y2345Argument of type '{ hex: string; }' is not assignable to parameter of type 'Point'. Type '{ hex: string; }' is missing the following properties from type 'Point': x, y
Try

类和对象在符合形状的方式上没有区别:

ts
class VirtualPoint {
x: number;
y: number;
 
constructor(x: number, y: number) {
this.x = x;
this.y = y;
}
}
 
const newVPoint = new VirtualPoint(13, 56);
logPoint(newVPoint); // logs "13, 56"
Try

如果对象或类具有所有必需的属性,TypeScript 就会认为它们匹配,而不论实现细节如何。

后续步骤

以上简要概述了日常使用 TypeScript 时涉及的语法和工具。接下来,你可以:

TypeScript 文档是一个开源项目。欢迎发送 Pull Request 帮助我们改进这些页面 ❤

最后更新于:2026 年 10 月 23 日