面向 JavaScript 开发者的 TypeScript

TypeScript 与 JavaScript 的关系不同寻常。TypeScript 提供了 JavaScript 的所有功能,并在其之上增加了一层:TypeScript 的类型系统。

例如,JavaScript 提供了诸如 stringnumber 这样的语言原语,但它不会检查你是否始终如一地分配了这些类型。而 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: stringid: 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 中已有一组可用的原始类型:booleanbigintnullnumberstringsymbolundefined,你可以在接口中使用它们。TypeScript 在此基础上扩展了一些类型,例如 any(允许任何内容)、unknown(确保使用此类型的人声明其确切类型)、never(此类型不可能发生)以及 void(返回 undefined 或没有返回值的函数)。

你会发现构建类型有两种语法:接口(Interfaces)和类型别名(Types)。你应该优先选择 interface。当需要特定功能时,再使用 type

组合类型

使用 TypeScript,你可以通过组合简单类型来创建复杂类型。有两种常用的方法:联合(Unions)和泛型(Generics)。

联合类型

通过联合,你可以声明一个类型可以是多种类型之一。例如,你可以将 boolean 类型描述为 truefalse

ts
type MyBool = true | false;
Try

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

联合类型的一个流行用例是描述允许作为值的 stringnumber 字面量 集合。

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

联合也提供了处理不同类型的方法。例如,你可能有一个接收 arraystring 的函数。

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"
函数 typeof f === "function"
数组 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 的核心原则之一是类型检查关注的是值的形状。这有时被称为“鸭子类型(duck typing)”或“结构化类型(structural typing)”。

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

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 来帮助我们改进这些页面 ❤

此页面的贡献者
OTOrta Therox (24)
JBJonathan Berger (1)
DSDustin Stender (1)
MKMatt Kantor (1)
JCRJuan Carlos Ruiz (1)
19+

最后更新:2026 年 3 月 27 日