Skip to content
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待
虚位以待

面向 JavaScript 程序员的 TypeScript

TypeScript 与 JavaScript 有着独特的关系。TypeScript 提供了 JavaScript 的所有特性,并在其之上增加了一层:TypeScript 的类型系统。

例如,JavaScript 提供了像 stringnumber 这样的语言原语,但它不会检查你是否始终如一地分配了这些类型。而 TypeScript 会。

这意味着你现有的可工作的 JavaScript 代码同时也是 TypeScript 代码。TypeScript 的主要好处是它可以突出代码中的意外行为,从而降低出现 bug 的可能性。

本教程简要概述了 TypeScript,重点关注其类型系统。

通过推断获得类型

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

ts
let 
helloWorld
= "Hello World";
Try

通过理解 JavaScript 的工作方式,TypeScript 可以构建一个接受 JavaScript 代码但具有类型的类型系统。这提供了一个类型系统,而无需在代码中添加额外的字符来显式指定类型。这就是 TypeScript 在上面的示例中知道 helloWorldstring 的方式。

你可能已经在 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'.
id
: 0,
};
Try

由于 JavaScript 支持类和面向对象编程,TypeScript 也支持。你可以将 interface 声明与类一起使用:

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 或没有返回值的函数)。

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

组合类型

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

联合

使用联合,你可以声明一个类型可能是多种类型中的一种。例如,你可以将 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

类型谓词
stringtypeof s === "string"
numbertypeof n === "number"
booleantypeof b === "boolean"
undefinedtypeof undefined === "undefined"
functiontypeof f === "function"
arrayArray.isArray(a)

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

ts
function 
wrapInArray
(
obj
: string | string[]) {
if (typeof
obj
=== "string") {
return [
obj
];
} 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
;
} // 这一行是一个快捷方式,告诉 TypeScript 有一个 // 名为 `backpack` 的常量,并且不用担心它来自哪里。 declare const
backpack
:
Backpack
<string>;
// object 是一个字符串,因为我们在上面将其声明为 Backpack 的变量部分。 const
object
=
backpack
.
get
();
// 由于 backpack 变量是一个字符串,你不能将数字传递给 add 函数。
backpack
.
add
(23);
Argument 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
}`);
} // 打印 "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
); // 打印 "12, 26"
const
rect
= {
x
: 33,
y
: 3,
width
: 30,
height
: 80 };
logPoint
(
rect
); // 打印 "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, 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
); // 打印 "13, 56"
Try

如果对象或类具有所有必需的属性,无论实现细节如何,TypeScript 都会说它们匹配。

下一步

这是对日常 TypeScript 中使用的语法和工具的简要概述。从这里开始,你可以: