Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

translate to simplified chinese #220

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

translate to simplified chinese #220

wants to merge 3 commits into from

Conversation

hexoh
Copy link

@hexoh hexoh commented Sep 27, 2023

Translation: Translate Everyday Types.md file into Simplified Chinese.

@github-actions
Copy link
Contributor

Thanks for the PR!

This section of the codebase is owned by @Kingwl - if they write a comment saying "LGTM" then it will be merged.

@github-actions
Copy link
Contributor

Translation of Everyday Types.md

title: Common types
layout: docs
permalink: /zh/docs/handbook/2/everyday-types.html

oneline: "The language primitives."

In this chapter, we will introduce some of the most common types of values in JavaScript code and explain the methods that describe the corresponding types in TypeScript.
This is not an exhaustive list, and subsequent chapters will describe more ways to name and use other types.

Types can also appear in many place, not just type annotations.
As we look at the types themselves, we'll also see where they can be referenced to form new structures.

We'll start by reviewing the most basic and common types you might encounter when writing JavaScript or TypeScript code.
These core building blocks later form more complex types.

Basic type:stringnumberand boolean

There are three very commonly used JavaScript uses Base type: stringnumber and boolean
Each has a corresponding type in TypeScript.
As you would expect, if you use JavaScript for these types of values typeof operator and you see these same names:

  • string Represents a string value, for example "Hello, world"
  • number Represents a number like this 42. JavaScript does not have a dedicated integer runtime value, so there is no equivalent int or float of the type, everything is number
  • boolean There are two values true and false

Type name StringNumber and Boolean(starting with a capital letter) is legal, but references some special built-in types that rarely appear in code. always use stringnumber or boolean as a type.

Arrays (array type)

To specify like [1, 2, 3] Such an array type can use syntax number[], this syntax works for any type (eg string[] is an array of strings, and so on).
You may also see it written as Array<number>, they mean the same thing.
We'll learn more about when we learn generics T<U> Knowledge of grammar.

Please note that[number] is a different thing, see the chapterTuple type

any

TypeScript also has a special type any, whenever you don't want a particular value to cause a type check error.

The type of the value is any , you can access any of its properties (will become any type), call it like a function, assign it to it any type of value (or from any type value), or any value that is syntactically legal:

let obj: any = { x: 0 };
// 以下代码行都不会引发编译器错误。
// 使用 `any` 会禁用所有进一步的类型检查,并且假设你比 TypeScript 更了解代码运行环境。
obj.foo();
obj();
obj.bar = 100;
obj = "hello";
const n: number = obj;

When you don't want to write a very long type just to make TypeScript believe that a particular line of code is okay,any Types are very useful.

noImplicitAny (Not included.) any Type)

When you do not specify a type, and TypeScript cannot infer the type from the context, the compiler usually defaults to it any Type.

However, you usually want to avoid this because any It is not type-checked.
Use compiler flags noImplicitAny Remove any implicit any for an error.

Type Annotations on Variables

When you use constvar or let When declaring a variable, you can optionally add a type annotation to explicitly specify the type of the variable:

let myName: string = "Alice";
//        ^^^^^^^^ 类型注释

TypeScript is not used 左侧类型 A declaration of a style, for example int x = 0;
The type comment is always in what you are typing afterwards

But in most cases, this is not needed.
Whenever possible, TypeScript will try to automatic deduce The type in the code.
For example, the type of a variable is inferred from the type of its initializer:

// 不需要类型注释 “myName”被推断为“string”类型
let myName = "Alice";

In most cases, you don't need to learn inference rules explicitly.
If you're just starting out, you should consider experimenting with fewer use of type annotations – you might be surprised that TypeScript requires very little content to fully understand what's going on.

Functions

Functions are the primary way to pass data in JavaScript.
TypeScript allows you to specify the types of input and output values for a function.

Parameter Type Annotations

When you declare a function, you can add a type comment after each parameter to declare the type of parameter that the function accepts.
The parameter type comment follows the parameter name:

// 参数类型注释
function greet(name: string) {
  //                 ^^^^^^^^
  console.log("Hello, " + name.toUpperCase() + "!!");
}

When a parameter has a type annotation, the function's parameters are checked:

// @errors: 2345
declare function greet(name: string): void;
// ---分割---
// 如果执行的话会出现运行时错误!
greet(42);

Even if you don't have type annotations on your parameters, TypeScript still checks that you've passed the correct number of arguments.

Return Type Annotations

You can also add a return type annotation.
The return type annotation appears after the parameter list:

function getFavoriteNumber(): number {
  //                        ^^^^^^^^
  return 26;
}

Much like variable type annotations, you typically don't need to return type annotations because TypeScript does so based on functions return The statement infers the return type of the function.
The type annotation in the example above does not change anything.
Some codebases explicitly specify the return type for documentation purposes to prevent accidental changes or just for personal preference.

Functions Which Return Promises

If you want to comment out the return type of a function that returns a Promise, you should use it Promise Type:

async function getFavoriteNumber(): Promise<number> {
  return 26;
}

Anonymous Functions

Anonymous functions are slightly different from function declarations.
When a function appears where TypeScript can make it clear how to call it, the function's parameters automatically specify the type.

Here is an example:

// @errors: 2551
const names = ["Alice", "Bob", "Eve"];

// 函数的上下文类型 - 推断参数具有字符串类型
names.forEach(function (s) {
  console.log(s.toUpperCase());
});

// 上下文类型也适用于箭头函数
names.forEach((s) => {
  console.log(s.toUpperCase());
});

Even parameters s There are no type annotations, TypeScript is also used forEach The type of the function is determined as well as the inferred array type s type.

This process is called Context type, because the function occurred context Determines what type it should have.

Similar to inference rules, you don't need to have a clear understanding of how this happens, but knowing that it does happen can help you notice when type annotations aren't needed.
Later, we'll see more examples of how the context in which a value appears affects its type.

Object Types

The most common types you'll encounter besides the basic ones are: Object type
This refers to almost any JavaScript value with any property!
To define an object type, we only need to list its properties and its type.

For example, this is a function that takes a point-like object:

// 参数的类型注解是对象类型
function printCoord(pt: { x: number; y: number }) {
  //                      ^^^^^^^^^^^^^^^^^^^^^^^^
  console.log("x坐标的值为 " + pt.x);
  console.log("y坐标的值为 " + pt.y);
}
printCoord({ x: 3, y: 7 });

Here, we use properties that have two properties ( x and y ) to annotate the parameter, both of which are properties number Type.
You can use it "," or ";" to separate the attributes, and the last separator is optional.

The type portion of each property is also optional.
If you do not specify a type, it is assumed to be any

Optional Properties

An object type can also specify that some or all of its properties are Optional
To do this, add after the property name "?"

function printName(obj: { first: string; last?: string }) {
  // ...
}
// 两种都可以
printName({ first: "Bob" });
printName({ first: "Alice", last: "Alisson" });

In JavaScript, if you access a property that doesn't exist, you get the value Yes undefined Instead of runtime errors.
Therefore, when you read from an optional property, you must check before using it undefined

// @errors: 2532
function printName(obj: { first: string; last?: string }) {
  // 错误 - 如果未提供“obj.last”,可能会意外错误。
  console.log(obj.last.toUpperCase());
  if (obj.last !== undefined) {
    // 正确
    console.log(obj.last.toUpperCase());
  }

  // 使用 JavaScript 最新语法的安全替代方案:
  console.log(obj.last?.toUpperCase());
}

Union Types

TypeScript's type system allows you to build new types from existing types using a variety of operators.
Now that we know how to write some types, it's time to start in a fun way combination They too.

Defining a Union Type

The first combination type you might see is the method united Type.
A union type is a type formed by two or more other types and a representation can be one of these types Any kind The value of the type.
We refer to each of these types as union member

Let's write a function that can operate on strings or numbers:

// @errors: 2345
function printId(id: number | string) {
  console.log("Your ID is: " + id);
}
// 正确
printId(101);
// 正确
printId("202");
// 错误
printId({ myID: 22342 });

Working with Union Types

offer The value that matches the union type is easy - just provide the type that matches any union member.
If you Yes A value of the union type, how do you use it?

TypeScript is only allowed for federations each Members are valid for the operation.
For example, if you have a federated type string | number, you cannot use only for string Method:

// @errors: 2339
function printId(id: number | string) {
  console.log(id.toUpperCase());
}

The solution is shrink The joint scope of the code, just like in JavaScript without type annotations.
This occurs when TypeScript can infer a more specific value type from the code structure shrink Range.

For example, TypeScript knows only string The value of the type is typeof The value is "string"

function printId(id: number | string) {
  if (typeof id === "string") {
    // 在此分支中,id 的类型为“string”
    console.log(id.toUpperCase());
  } else {
    // 这里,id 的类型是“number”
    console.log(id);
  }
}

Another example is the use of likes Array.isArray Function like this:

function welcomePeople(x: string[] | string) {
  if (Array.isArray(x)) {
    // 这里:“x”是“string[]”
    console.log("Hello, " + x.join(" and "));
  } else {
    // 这里:“x”是“string”
    console.log("Welcome lone traveler " + x);
  }
}

Note that in else branches, we don't need to do anything special - if x No string[], then it must be string

Sometimes, you build a union in which all members have something in common.
For example, both arrays and strings have one slice Method.
If each member of the union has a property in common, you can use that property without narrowing the scope:

// 返回类型被推断为 number[] | string
function getFirstThree(x: number[] | string) {
  return x.slice(0, 3);
}

Confusingly, type united Appears to have properties of these types intersection
This is no accident – the name union comes from type theory.
Federated type number | string by each type Value is composed of unions.
Note that given two sets and the facts of each set match, only those facts intersection Applies to the collection itself union
For example, if we have a room full of tall people wearing hats and Spanish speakers in another room wearing hats, then after combining these rooms, we are right each The only thing people understand is that they must be wearing hats.

Type Aliases

We have been using them by writing object types and union types directly in type annotations.
But often you want to easily use the same type multiple times and refer to it by a name.

Type alias Exactly like that - arbitrary type target name
The syntax for type aliases is:

type Point = {
  x: number;
  y: number;
};

// 与前面的示例完全相同
function printCoord(pt: Point) {
  console.log("The coordinate's x value is " + pt.x);
  console.log("The coordinate's y value is " + pt.y);
}

printCoord({ x: 100, y: 100 });

In fact, you can use type aliases to name any type, not just object types.
For example, a type alias can name a union type:

type ID = number | string;

Note that aliases are just aliases - you can't use type aliases to create different/deterministic ones of the same type 版本
When you use an alias, it is as if you had written an alias type.
In other words, this code may looks Illegal, but according to TypeScript it is okay because both types are aliases of the same type:

declare function getInput(): string;
declare function sanitize(str: string): string;
// ---分割---
type UserInputSanitizedString = string;

function sanitizeInput(str: string): UserInputSanitizedString {
  return sanitize(str);
}

// 创建经过美化的输入
let userInput = sanitizeInput(getInput());

// 但仍然可以用字符串重新分配
userInput = "new input";

Interfaces

Interface declaration is another way to name object types:

interface Point {
  x: number;
  y: number;
}

function printCoord(pt: Point) {
  console.log("x坐标的值为 " + pt.x);
  console.log("y坐标的值为 " + pt.y);
}

printCoord({ x: 100, y: 100 });

Just like we used type aliases above, the example works just like we use anonymous object types.
TypeScript only cares about what we pass on printCoord of the value structure - It only cares if it has the expected properties.
Caring only about the structure and functionality of a type is what we call TypeScript Structure type The reason for the system.

Differences Between Type Aliases and Interfaces

Type aliases and interfaces are very similar, and in many cases you are free to choose between them.
almost interface All features are available in type , the key difference is that types cannot be reopened (assigned or created) to add new properties, while interfaces are always extensible.

Interface Type

扩展接口

interface Animal {
  name: string;
}
interface Bear extends Animal { honey: boolean; }
const bear = getBear(); bear.name; bear.honey;

通过交集扩展类型

type Animal = {
  name: string;
}
type Bear = Animal & { honey: boolean; }
const bear = getBear(); bear.name; bear.honey;

向现有接口添加新字段

interface Window {
  title: string;
}
interface Window { ts: TypeScriptAPI; }
const src = 'const a = "Hello World"'; window.ts.transpileModule(src, {});

类型创建后不能更改

type Window = {
  title: string;
}
type Window = { ts: TypeScriptAPI; }
// Error: Duplicate identifier 'Window'. (错误:重复的标识符 'Window'。)

You'll learn more about these concepts in later chapters, so don't worry if you can't understand all of them right away.

Most of the time, you can choose according to your personal preference, and TypeScript will tell you if you need other types of declarations. If you want a heuristic, use interfaceuntil you need to use it typefeatures in .

Type Assertions

Sometimes you have information about value types that TypeScript can't understand.

For example, if you are using document.getElementById, TypeScript only knows that this will return some sort of thing HTMLElement, but you probably know that your page will always have one with a given ID HTMLCanvasElement

In this case, you can use Type assertions to specify a more specific type:

const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;

Like type annotations, type assertions are removed by the compiler and do not affect the behavior of the code when it runs.

You can also use angle bracket syntax (unless the code is located in .tsx file), it is equivalent to:

const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");

Note: Because type assertions are removed at compile time, there are no runtime checks related to type assertions.
If the type assertion is incorrect, no exception OR is generated null

TypeScript only allows type assertion conversion Be more specific or Not too specific The type version.
This rule prevents 不可能 of coercion, such as:

// @errors: 2352
const x = "hello" as number;

Sometimes, this rule can be too conservative and does not allow for more complex enforcement that may be effective.
If this happens, you can use two assertions, the first is any(or unknown, which we'll cover later), and then the type required:

declare const expr: any;
type T = { a: 1; b: 2; c: 3 };
// ---分割---
const a = expr as any as T;

Literal Types

In addition to generic types string and number In addition, we can also reference at the type location specific Strings and numbers.

One way to think about this is to consider how JavaScript declares variables in different ways. var and let Both allow changing the contents saved within the variable instead const is not allowed.
This is reflected in how TypeScript creates types for text.

let changingString = "Hello World";
changingString = "Olá Mundo";
// 因为 `changingString` 可以表示任何可能的字符串,这就是 TypeScript 在类型系统中描述它的方式
changingString;
// ^?

const constantString = "Hello World";
// 因为 `constantString` 只能表示 1 个可能的字符串,所以它有一个文字类型表示
constantString;
// ^?

On its own, text types are not very valuable:

// @errors: 2322
let x: "hello" = "hello";
// OK
x = "hello";
// ...
x = "howdy";

A variable that can only have one value is not very useful!

But by text combination Together, you can express more useful concepts - for example, functions that accept only a specific set of known values:

// @errors: 2345
function printText(s: string, alignment: "left" | "right" | "center") {
  // ...
}
printText("Hello, world", "left");
printText("G'day, mate", "centre");

Numeric literal types work the same way:

function compare(a: string, b: string): -1 | 0 | 1 {
  return a === b ? 0 : a > b ? 1 : -1;
}

Of course, you can combine them with non-text types:

// @errors: 2345
interface Options {
  width: number;
}
function configure(x: Options | "auto") {
  // ...
}
configure({ width: 100 });
configure("auto");
configure("automatic");  // error: Argument of type '"automatic"' is not assignable to parameter of type 'Options | "auto"'

There is another type of text: the Boolean type.
There are only two Boolean text types, and as you might guess, they are true and false Type.
type boolean In itself, it's really just union true | false alias of .

Literal Inference (literal reasoning)

When you initialize a variable with an object, TypeScript assumes that the object's properties might change values later.
For example, if you write code like this:

declare const someCondition: boolean;
// ---分割---
const obj = { counter: 0 };
if (someCondition) {
  obj.counter = 1;
}

TypeScript does not assume will 1 Assigned to previously had 0 The field is wrong.
Another way of saying it is obj.counter Must have number type, instead 0, because the type is used to determine Read and write Behavior.

The same applies to strings:

// @errors: 2345
declare function handleRequest(url: string, method: "GET" | "POST"): void;
// ---分割---
const req = { url: "https://example.com", method: "GET" };
handleRequest(req.url, req.method);

In the example above,req.method is inferred as stringInstead of "GET"。 Because the code can be created req and invoke handleRequest This can be evaluated like "GUESS" Such a new string is assigned to req.method, so TypeScript thinks this code is wrong.

There are two ways to solve this problem.

  1. You can change the inference by adding a type assertion in either place:

    declare function handleRequest(url: string, method: "GET" | "POST"): void;
    // ---分割---
    // Change 1:
    const req = { url: "https://example.com", method: "GET" as "GET" };
    // Change 2
    handleRequest(req.url, req.method as "GET");

    Change 1 means "I intend to make req.method Always have Text type "GET"", thus preventing possible aftermath "GUESS" Assigned to the field.
    Change 2 means "I know for other reasons." req.method The value is "GET"

  2. You can use it as const To convert an entire object to type literal:

    declare function handleRequest(url: string, method: "GET" | "POST"): void;
    // ---分割---
    const req = { url: "https://example.com", method: "GET" } as const;
    handleRequest(req.url, req.method);

as const The function of the suffix is similar to const, but for the type system, make sure that all properties are assigned as literal types, not like them string or number Such a more generic version.

null and undefined and 未定义

JavaScript has two primitive values to represent values that do not exist or are not initialized:null and undefined

TypeScript has two corresponding ones with the same name type 。 How these types behave depends on whether you have enabled them strictNullChecks Options.

strictNullChecks off (Off严格的空检查

Shut down strictNullChecks After that, you can still access normally as possible null or undefined and can be valued null and undefined Assigned to any type of property.
This is similar to how languages without null checking (e.g. C#, Java) behave.
Lack of checking for these values is often a major source of error; If it works in the codebase, we always recommend opening it strictNullChecks

strictNullChecks on (enables strict null checking)

enable strictNullChecks After that, the value is null or undefined , you need to test the values before using methods or properties on them.
Just like checking before using optional attributes undefined Again, we can use narrowing to check what might be null Value:

function doSomething(x: string | null) {
  if (x === null) {
    // 没做什么
  } else {
    console.log("Hello, " + x.toUpperCase());
  }
}

Non-null Assertion Operator (Postfix !(non-null assertion operator (suffix.)!))

TypeScript also has a special syntax that can be removed from types null and undefinedwithout any explicit checking.
Write after any expression ! It is actually a type assertion indicating that the value is not null or undefined

function liveDangerously(x?: number | null) {
  // 没有错误
  console.log(x!.toFixed());
}

Just like other types of assertions, this does not change the runtime behavior of the code, so when you know the value No for null or undefined , use only ! Very important.

Enums (enumeration)

Enumerations are a feature added to JavaScript by TypeScript that allows you to describe a value, which can be one of a set of possible named constants. Unlike most TypeScript features, this No JavaScript is added at the type level, but instead added to the language and runtime stuff. Therefore, you should be aware of the presence of the feature, but unless you are sure, it may be postponed. You can find it inEnumerate reference pagesRead more about enumerations.

Less Common Primitives

It is still necessary to explain the other basic types represented in JavaScript in the type system.
Although we won't delve into it here.

bigint (Large integer)

Starting with ES2020, there is a basic type in JavaScript for very large integers,BigInt

// @target: es2020

// 通过 BigInt 函数创建 bigint
const oneHundred: bigint = BigInt(100);

// 通过文字语法创建 BigInt
const anotherHundred: bigint = 100n;

You can find it in TypeScript 3.2 release notes Learn more about BigInt.

symbol

There is a basic type in JavaScript for passing functions Symbol() To create a globally unique reference:

// @errors: 2367
const firstName = Symbol("name");
const secondName = Symbol("name");

if (firstName === secondName) {
  // 永远不可能发生
}

You can find it in Symbols reference pageLearn more about them.

Generated by 🚫 dangerJS against 85df0aa

@hexoh
Copy link
Author

hexoh commented Sep 27, 2023

@microsoft-github-policy-service agree

@awxiaoxian2020
Copy link
Contributor

Please Move On https://github.com/ts-zh-docs/TypeScript-zh-Website.
This l18n will shut down soon according microsoft/TypeScript-Website#2804

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants