TypeScript stands in an unusual relationship to JavaScript. TypeScript offers all of JavaScript’s features, and an additional layer on top of these: TypeScript’s type system.
Typescript与JavaScript有着不同寻常的关系。TypeScript提供了JavaScript的所有特性,在这些特性之上还有额外的一层:TypeScript的类型系统。
For example, JavaScript provides language primitives like string, number, and object, but it doesn’t check that you’ve consistently assigned these. TypeScript does.
例如,JavaScript提供了像stringnumberobject这样的语言的基础类型,但它不会检查你是否一致地分配了这些基础类型。TypeScript却可以。
This means that your existing working JavaScript code is also TypeScript code. The main benefit of TypeScript is that it can highlight unexpected behavior in your code, lowering the chance of bugs.
这意味着你现有的JavaScript代码也是TypeScript代码。TypeScript的主要好处是它可以突出代码中的意外行为,降低出现错误的几率。
This tutorial provides a brief overview of TypeScript, focusing on its type system.
本教程简要介绍Typescript,重点介绍它的类型系统。

Types by Inference

类型推断

TypeScript knows the JavaScript language and will generate types for you in many cases. For example in creating a variable and assigning it to a particular value, TypeScript will use the value as its type.
Typescript了解JavaScript语言,在很多情况下会为你生成类型。例如,在创建一个变量并将其赋值给一个特定的值时,TypeScript会使用这个值作为它的类型。

  1. let helloWorld = "Hello World";
  2. // ^ = let helloWorld: string

By understanding how JavaScript works, TypeScript can build a type-system that accepts JavaScript code but has types. This offers a type-system without needing to add extra characters to make types explicit in your code. That’s how TypeScript knows that helloWorld is a string in the above example.
通过理解JavaScript是如何工作的,Typescript可以构建一个类型系统,它接受JavaScript代码,但是有类型。这提供了一个类型系统,而不需要添加额外的字符来在代码中显式地显示类型。这就是为什么TypeScript知道上面例子中的helloworld是一个字符串。
You may have written JavaScript in Visual Studio Code, and had editor auto-completion. Visual Studio Code uses TypeScript under the hood to make it easier to work with JavaScript.
你可能用VS Code编写过Javascript,并拥有编辑器自动完成功能。VS Code在底层使用TypeScript,让JavaScript更容易使用。

Defining Types

类型定义

You can use a wide variety of design patterns in JavaScript. However, some design patterns make it difficult for types to be inferred automatically (for example, patterns that use dynamic programming). To cover these cases, TypeScript supports an extension of the JavaScript language, which offers places for you to tell TypeScript what the types should be.
你可以在JavaScript中使用各种各样的设计模式。然而,一些设计模式使类型难以自动推断(例如,使用动态编程的模式)。为了涵盖这些情况,TypeScript支持Javascript语言的扩展,它为你提供了地方告诉TypeScript应该是什么类型。
For example, to create an object with an inferred type which includes name: string and id: number, you can write:
例如,要创建一个具有推断类型(如name: string和id: number)的对象,你可以这么写:

  1. const user = {
  2. name: "Hayes",
  3. id: 0,
  4. };

You can explicitly describe this object’s shape using an interface declaration:
你可以使用interface声明来显式地描述这个对象的形状:

  1. interface User {
  2. name: string;
  3. id: number;
  4. }

You can then declare that a JavaScript object conforms to the shape of your new interface by using syntax like : TypeName after a variable declaration:
然后,你可以在变量声明后使用: TypeName 语法来声明一个JavaScript对象符合你的新接口的形状:

  1. const user: User = {
  2. name: "Hayes",
  3. id: 0,
  4. };

If you provide an object that doesn’t match the interface you have provided, TypeScript will warn you:
如果你提供的对象与你提供的接口不匹配,Typescript会警告你:

  1. interface User {
  2. name: string;
  3. id: number;
  4. }
  5. const user: User = {
  6. username: "Hayes",
  7. Type '{ username: string; id: number; }' is not assignable to type 'User'.
  8. Object literal may only specify known properties, and 'username' does not exist in type 'User'.2322Type '{ username: string; id: number; }' is not assignable to type 'User'.
  9. Object literal may only specify known properties, and 'username' does not exist in type 'User'.
  10. id: 0,
  11. };

Since JavaScript supports classes and object-oriented programming, so does TypeScript. You can use an interface declaration with classes:
自从JavaScript支持类和面向对象编程,Typescript也一样。你可以在类中使用接口声明:

  1. interface User {
  2. name: string;
  3. id: number;
  4. }
  5. class UserAccount {
  6. name: string;
  7. id: number;
  8. age: number;
  9. constructor(name: string, id: number, age: number) {
  10. this.name = name;
  11. this.id = id;
  12. this.age = age
  13. }
  14. }
  15. const user: User = new UserAccount("Murphy", 1, 18);
  16. user.age // 类型“User”上不存在属性“age”。
  17. // user还是只有 name和id 两个属性,没有age

You can use interfaces to annotate parameters and return values to functions:
你可以使用接口来定义函数的参数和返回值:

  1. function deleteUser(user: User) {
  2. // ...
  3. }
  4. function getAdminUser(): User {
  5. //...
  6. }

There are already a small set of primitive types available in JavaScript: boolean, bigint, null, number, string, symbol, object, and undefined, which you can use in an interface. TypeScript extends this list with a few more, such as any (allow anything), unknown (ensure someone using this type declares what the type is), never (it’s not possible that this type could happen), and void (a function which returns undefined or has no return value).
Javascript中已经有一部分基本类型可用:boolean, bigint, null, number, string, symbol, object, 和 undefined,你可以在接口中使用它们。TypeScript扩展了这个列表,比如any (允许任何类型)、unknown(确保使用该类型的人声明了该类型是什么)、never(不可能出现这种类型)和void(返回undefined或没有返回值的函数)。
You’ll see that there are two syntaxes for building types: Interfaces and Types. You should prefer interface. Use type when you need specific features.
构建类型有两种语法:接口和类型。你更应该选择interface。只在需要特定功能时使用type

Composing Types

组合类型

With TypeScript, you can create complex types by combining simple ones. There are two popular ways to do so: with Unions, and with Generics.
使用TypeScript,你可以通过组合简单的类型来创建复杂的类型。有两种常用的方法可以做到这一点:联合和泛型。

Unions

联合

With a union, you can declare that a type could be one of many types. For example, you can describe a boolean type as being either true or false:
使用联合,你可以声明一个类型可以是许多类型中的一种。例如,你可以将一个布尔类型描述为true或false:

  1. type MyBool = true | false;

Note: If you hover over MyBool above, you’ll see that it is classed as boolean. That’s a property of the Structural Type System. More on this below.
注意:如果你把鼠标悬停在MyBool上面,你会看到它被归为布尔型。这是结构类型系统的一种属性。下面有更多的介绍。
A popular use-case for union types is to describe the set of strings or numbers literal that a value is allowed to be:
union类型的一个流行用例是描述一个值是字符串或数字的集合:

  1. type WindowStates = "open" | "closed" | "minimized";
  2. type LockStates = "locked" | "unlocked";
  3. type OddNumbersUnderTen = 1 | 3 | 5 | 7 | 9;

Unions provide a way to handle different types too. For example, you may have a function that takes an array or a string:
联合也提供了一种处理不同类型的方法。例如,你可能有一个接受数组或字符串的函数:

  1. function getLength(obj: string | string[]) {
  2. return obj.length;
  3. }

To learn the type of a variable, use typeof:
要知道变量的类型,请使用typeof

Type Predicate
string typeof s === "string"
number typeof n === "number"
boolean typeof b === "boolean"
undefined typeof undefined === "undefined"
function typeof f === "function"
array Array.isArray(a)

For example, you can make a function return different values depending on whether it is passed a string or an array:
例如,可以根据传递给函数的参数是字符串还是数组,可以让函数返回不同的值:

  1. function wrapInArray(param: string | string[]) {
  2. if (typeof param === "string") {
  3. return [param];
  4. // ^ = (parameter) param: string
  5. } else {
  6. return param;
  7. }
  8. }

Generics

泛型

Generics provide variables to types. A common example is an array. An array without generics could contain anything. An array with generics can describe the values that the array contains.
泛型为类型提供变量。一个常见的例子是数组。没有泛型的数组可以包含任何东西。具有泛型的数组可以描述数组包含的值。

  1. type StringArray = Array<string>;
  2. type NumberArray = Array<number>;
  3. type ObjectWithNameArray = Array<{ name: string }>;

You can declare your own types that use generics:
你可以声明自己使用泛型的类型:

  1. interface Backpack<Type> {
  2. add: (obj: Type) => void;
  3. get: () => Type;
  4. }
  5. declare const backpack: Backpack<string>; // 这一行是告诉TypeScript有一个名为“backpack”的常量的快捷方式,不用担心它来自哪里。
  6. const object = backpack.get(); // object是一个字符串,因为我们在上面将它声明为Backpack的变量部分。
  7. backpack.add(23); // 报错:由于backpack的变量是一个字符串,所以不能将数字传递给add函数。
  8. // 类型'number'的实参不能赋值给类型为'string'的形参。

Structural Type System

结构类型系统

One of TypeScript’s core principles is that type checking focuses on the shape that values have. This is sometimes called “duck typing” or “structural typing”.
TypeScript的核心原则之一是类型检查关注的是值所具有的形状。这有时被称为”鸭子类型”或”结构类型”
In a structural type system, if two objects have the same shape, they are considered to be of the same type.
在一个结构类型系统中,如果两个对象具有相同的形状,则认为它们属于同一类型。

  1. interface Point {
  2. x: number;
  3. y: number;
  4. }
  5. function logPoint(p: Point) {
  6. console.log(`${p.x}, ${p.y}`);
  7. }
  8. const point = { x: 12, y: 26 };
  9. logPoint(point);

The point variable is never declared to be a Point type. However, TypeScript compares the shape of point to the shape of Point in the type-check. They have the same shape, so the code passes.
point变量没有声明为Point类型。然而,TypeScript会在类型检查中将point变量的形状与Point类型的形状进行比较。它们有相同的形状,所以代码通过。
The shape-matching only requires a subset of the object’s fields to match.
形状匹配只需要对象字段的一个子集来匹配(即传入的对象必须包含接口类型)。

  1. const point3 = { x: 12, y: 26, z: 89 };
  2. logPoint(point3); // logs "12, 26"
  3. const rect = { x: 33, y: 3, width: 30, height: 80 };
  4. logPoint(rect); // logs "33, 3"
  5. const color = { hex: "#187ABF" };
  6. logPoint(color); // 参数类型'{ hex: string; }' 不能赋值给类型为'Point'的形参。类型'{ hex: string; }' 丢失'Point'类型的以下属性: x, y

There is no difference between how classes and objects conform to shapes:
类和对象在遵循形状方面没有区别:

  1. class VirtualPoint {
  2. x: number;
  3. y: number;
  4. constructor(x: number, y: number) {
  5. this.x = x;
  6. this.y = y;
  7. }
  8. }
  9. const newVPoint = new VirtualPoint(13, 56);
  10. logPoint(newVPoint); // logs "13, 56"

If the object or class has all the required properties, TypeScript will say they match, regardless of the implementation details.
如果对象或类拥有共同的属性,TypeScript会说它们匹配,而不管实现细节如何。

Next Steps

下一步

This was a brief overview of the syntax and tools used in everyday TypeScript. From here, you can:
这是一个日常Typescript中使用的语法和工具的简要概述。从这里,你可以: