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 _Type Manipulation_ Into Chinese #120

Closed
wants to merge 16 commits into from

Conversation

zhouLion
Copy link

  • Markdown Files: documents of Type Manipulation of handbook-v2
  • Language: Chinese

@ghost
Copy link

ghost commented Sep 12, 2021

CLA assistant check
All CLA requirements met.

@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

github-actions bot commented Sep 12, 2021

Translation of Angular.md

title: Angular
layout: docs
permalink: /zh/docs/handbook/angular.html
oneline: Use TypeScript in Angular

deprecated: true

Angular is a modern framework built entirely from TypeScript, so combining TypeScript with Angular provides a seamless experience.

Angular documentation supports TypeScript as a Tier 1 citizen and as the primary language. With that in mind,Angular's website Will always be the latest reference to use Angular and TypeScript.

View [Quick start guidelines]](https://angular.io/docs/ts/latest/quickstart.html) Start learning Angular!

Translation of Type Checking JavaScript Files.md

title: Type Checking JavaScript Files
layout: docs
permalink: /zh/docs/handbook/type-checking-javascript-files.html

oneline: How to add type checks to JavaScript files using TypeScript

and .ts Compared to the file,.js There are some obvious differences in the mechanism of checking documents.

The property is inferred from the assignment in the body of the class

ES2015 has no way to declare its properties within a class. Properties are dynamically assigned, just like the literal amount of an object.

at .js In the file, the compiler infers the property from the property assignment in the class body.
The type of the property is the type given in the constructor, unless it is not specified there, or it is undefined or null specified in the constructor.
Therefore, the type is a set of all the right-hand values in these assignments.
Properties defined in constructors are always set to exist, and those defined in methods, getters, or setters are considered optional.

// @checkJs
// @errors: 2322
class C {
  constructor() {
    this.constructorOnly = 0;
    this.constructorUnknown = undefined;
  }
  method() {
    this.constructorOnly = false;
    this.constructorUnknown = "plunkbat"; // 没问题,constructorUnknown 的类型是 string | undefined
    this.methodOnly = "ok"; // 没问题,但是 methodOnly 的类型依然是 undefined
  }
  method2() {
    this.methodOnly = true; // 也没有问题, methodOnly 的类型是 string | boolean | undefined
  }
}

If properties have never been set in the class body, they are considered unknown.
If your class has read-only properties, add a declaration to the constructor and comment it with JSDoc to specify the type.
If you don't initialize it until later, you don't even have to give a value:

// @checkJs
// @errors: 2322
class C {
  constructor() {
    /** @type {number | undefined} */
    this.prop = undefined;
    /** @type {number | undefined} */
    this.count;
  }
}

let c = new C();
c.prop = 0; // OK
c.count = "string";

Constructors are equivalent to classes

Prior to ES2015, JavaScript used constructor functions instead of classes.
The compiler supports this pattern and interprets the constructor function as a class equivalent to ES2015.
The inference rules for properties are exactly the same as above.

// @checkJs
// @errors: 2683 2322
function C() {
  this.constructorOnly = 0;
  this.constructorUnknown = undefined;
}
C.prototype.method = function () {
  this.constructorOnly = false;
  this.constructorUnknown = "plunkbat"; // OK, the type is string | undefined
};

CommonJS modules are supported

in one .js In the file, TypeScript understands the CommonJS module format.
exports and module.exports The assignment of is recognized as an export declaration.
Similarly, require The call to the method is considered module introduction. For example:

// 等同 `import module "fs"`
const fs = require("fs");

// 等同 `export function readFile`
module.exports.readFile = function (f) {
  return fs.readFileSync(f);
};

In syntax, the modules in Javascript are more supported than typeScript.
It supports the combination of most assignments and declarations.

Types, functions, and object literals are namespaces

at .js In the file, the type is the namespace.
It can be used to nest types, such as:

class C {}
C.D = class {};

Also, for code prior to ES2015, it can be used to mimic static methods:

function Outer() {
  this.y = 2;
}

Outer.Inner = function () {
  this.yy = 2;
};

Outer.Inner();

It can also be used to create a simple namespace:

var ns = {};
ns.C = class {};
ns.func = function () {};

ns;

Other variants are also supported:

// IIFE
var ns = (function (n) {
  return n || {};
})();
ns.CONST = 1;

// defaulting to global
var assign =
  assign ||
  function () {
    // code goes here
  };
assign.extra = 1;

The literal amount of the object is open

One .ts In a file, an object that initializes a variable declaration literally gives it the type of declaration.
New members that are not specified in the original literal amount are not allowed.
The rule is in .js The file becomes loose; the object literally has this open type (index signature), which allows you to add and view properties that were not originally defined.
Like what:

var obj = { a: 1 };
obj.b = 2; // Allowed

This behavior of the literal amount of an object is as if it had an index signature [x:string]: any, so that it is treated as an open map, not as a closed object.
Just like other special JS check behaviors, these behaviors can be changed by specifying a JSDoc type for their variables. Like what:

// @checkJs
// @errors: 2339
/** @type {{a: number}} */
var obj = { a: 1 };
obj.b = 2;

The null, undefined, and empty arrays are initialized to any or any

Any variable, argument, or property, once initialized as null or undefined, the type will be any, even if strict is turned on null examine.
Any variable, argument, or property, once initialized as [] , its type will be any[], even if it's turned on strictly null examine.
The only exception is a property that has multiple initial value setters, as described above.

function Foo(i = null) {
  if (!i) i = 1;
  var j = undefined;
  j = 2;
  this.l = [];
}

var foo = new Foo();
foo.l.push(foo.i);
foo.l.push("end");

The function's arguments are optional by default

Because there was no way to make parameters optional in JavaScript prior to ES2015, it was not available .js The parameters of all methods are considered optional.
The arguments passed at the time of the call are less than the number declared and are allowed.

It is important to note that it is wrong to pass too many arguments at the time of the call.

Like what:

// @checkJs
// @strict: false
// @errors: 7006 7006 2554
function bar(a, b) {
  console.log(a + " " + b);
}

bar(1); // 没问题,第二个参数被视为可选
bar(1, 2);
bar(1, 2, 3); // 报错了,传递过多的参数

The function of the JSDoc comment is not included in this rule.
Using the JSDoc optional parameter syntax ([ ]to represent optionality. Like what:

/**
 * @param {string} [somebody] - Somebody's name.
 */
function sayHello(somebody) {
  if (!somebody) {
    somebody = "John Doe";
  }
  console.log("Hello " + somebody);
}

sayHello();

Used arguments The Var-args parameter declaration of inference

If a function body references arguments Reference, implicitly assumes that the function has a var-arg argument (as if(...arg: any[]) => any)。 Use JSDoc's var-arg syntax to specify the type of argument.

/** @param {...number} args */
function sum(/* numbers */) {
  var total = 0;
  for (var i = 0; i < arguments.length; i++) {
    total += arguments[i];
  }
  return total;
}

Arguments of an unspecified type are considered any type

Because there is no natural syntax for generic type parameters specified in JavaScript, the default is for parameters that are formulated for types any

In the extends clause

For example, React.Component Is defined as having two parameters, which are Props and State
at .js In the file, there is no reasonable way to specify them in the extension clause, so these two parameters are any

import { Component } from "react";

class MyComponent extends Component {
  render() {
    this.props.b; // Allowed, since this.props is of type any
  }
}

use @augments to specify the type explicitly. Like what:

import { Component } from "react";

/**
 * @augments {Component<{a: number}, State>}
 */
class MyComponent extends Component {
  render() {
    this.props.b; // Error: b does not exist on {a:number}
  }
}

In the JSDoc reference

The parameters of the type not specified in JSDoc default to any:

/** @type{Array} */
var x = [];

x.push(1); // 没问题
x.push("string"); // 没问题, x 的类型为 Array<any>

/** @type{Array.<number>} */
var y = [];

y.push(1); // 没问题
y.push("string"); // 报错, string 不能飞配给 number 类型

In a function call

A call to a generic function that uses generic parameters to infer type parameters. Sometimes this process cannot infer any type, mainly because of the lack of inferred sources; any。 Like what:

var p = new Promise((resolve, reject) => {
  reject();
});

p; // Promise<any>;

See for all the features available in JSDoc This manual

Translation of Intro to JS with TS.md

title: JS Projects Utilizing TypeScript
layout: docs
permalink: /zh/docs/handbook/intro-to-js-ts.html
oneline: How to add type checks to JavaScript files using TypeScript

translatable: true

TypeScript's type systems have different levels of rigour in different code bases:

  • Type systems that are inferred only from JavaScript code
  • In JavaScript Via JSDoc Increase the type
  • Used in JavaScript files // @ts-check
  • TypeScript code
  • TypeScript code, which strict Set to on

Each step represents a step toward a more secure type system, but not every project requires this level of validation.

TypeScript with JavaScript

That's when you use an editor that uses TypeScript to provide tools such as auto-complement, identity jump, and refactoring tools like renaming.
at Home There is an editor list with your own TypeScript plug-in.

Provide type tips in JS with JSDoc

in one .js In a file, type is usually inferred. They can also be specified using the JSDoc syntax when the type cannot be inferred.

JSDoc comments appear before a declaration and will be used to set the type of claim. For example:

/** @type {number} */
var x;

x = 0; // OK
x = false; // OK?!

You can do it Types supported by JSDoc Find a complete list of patterns supported by JSDoc.

@ts-check

The last line in the code example above raises an error in TypeScript, but not in the JS project by default.
To make it report errors in your JavaScript, add: // @ts-check to yours .js On the first line of the file, let TypeScript trigger the error.

// @ts-check
// @errors: 2322
/** @type {number} */
var x;

x = 0; // OK
x = false; // Not OK

If you have a large number of JavaScript files, if you want to add error prompts, you can switch to use them jsconfig.json
You can add to the file by adding it // @ts-nocheck Comment to skip checks on individual files.

TypeScript can sometimes have unexpected errors, which you can add on the previous line // @ts-ignore or // @ts-expect-error to ignore these errors.

// @ts-check
/** @type {number} */
var x;

x = 0; // OK
// @ts-expect-error
x = false; // Not OK

To learn how JavaScript is explained by TypeScript, see How the TS type checks JS

Translation of Creating DTS files From JS.md

title: Creating .d.ts Files from .js files
layout: docs
permalink: /zh/docs/handbook/declaration-files/dts-from-js.html
oneline: "How to build and add .d.ts to JavaScript projects"

translatable: true

Use TypeScript 3.7,
TypeScript adds support for generating .d.ts files for JavaScript that uses the JSDoc syntax.

This setup means that you can have an editor experience with TypeScript-supported editors without having to port projects to TypeScript or maintain .d.ts files in your code base.

TypeScript supports the vast majority of JSDoc tags, which you can refer to Here's the manual

Configure your project to output .d.ts files

To add a build of a .d.ts file to your project, you need to perform up to four steps:

  • Add TypeScript to your development dependencies
  • Add one tsconfig.json to configure TypeScript
  • Run the TypeScript compiler to generate the d.ts file for the JS file
  • (Optional) Edit package.json to specify the type file

Add TypeScript

You can find it at our The installation page learn how to add.

TSConfig

TSConfig is a jsonc file that is configured with your compiler tag and has stated where to find the file.
In this case, you will need a file like this:

{
  // Change this to match your project
  "include": ["src/**/*"],

  "compilerOptions": {
    // Tells TypeScript to read JS files, as
    // normally they are ignored as source files
    "allowJs": true,
    // Generate d.ts files
    "declaration": true,
    // This compiler run should
    // only output d.ts files
    "emitDeclarationOnly": true,
    // Types should go into this directory.
    // Removing this would place the .d.ts files
    // next to the .js files
    "outDir": "dist"
  }
}

You can do it tsconfig reference Learn more about configurations.
Another option to use TSConfig is both the CLI, which behaves like a CLI directive.

npx -p typescript tsc src/**/*.js --declaration --allowJs --emitDeclarationOnly --outDir types

Run the compiler

You can find it at our The installation page learn how to operate.

You want to make sure these files are included in your package if you have the files in your project's .gitignore.

Edit package.json

TypeScript copied package.json node resolution in the module, plus a lookup .d.ts The steps of the file.
Roughly, the parsing will be from an optional one "types" Start checking, then "main" field, and then try to find the item under the root index.d.ts

Package.json The default location of .d.ts
No "types" field Check "main", followed by index.d.ts
"types": "main.d.ts" main.d.ts
"types": "./dist/main.js" ./dist/main.d.ts

If it is missing, look for the "main" field

Package.json The default location of .d.ts
There is no "main" field index.d.ts
"main":"index.js" index.d.ts
"main":"./dist/index.js" ./dist/index.d.ts

Tips

If you want to write a test for your .d.ts file, try this tsd.

Translation of _Creating Types from Types.md

title: Creating Types from Types
layout: docs
permalink: /zh/docs/handbook/2/types-from-types.html

oneline: "An overview of several ways to create more types from existing types."

TypeScript's type system is very powerful because it allows you to represent types in other types.

The simplest form of this statement is generic, and we actually have a variety of type operators.
You can also use what we already have value to represent the type.

By combining various types of operators, we can express complex operations and values in a concise, maintainable manner.
In this section, we'll look at ways to represent a new type with an existing type or value.

Translation of Typeof Type Operator.md

title: Typeof Type Operator
layout: docs
permalink: /zh/docs/handbook/2/typeof-types.html

oneline: "Use typeof operators in type context"

typeof Type operator

In JavaScript, there are already applications available expression Context typeof operator.

// Prints "string"
console.log(typeof "Hello world");

TypeScript is new and can be used in type Context typeofto infer a variable or property type

let s = "hello";
let n: typeof s;
//  ^?

This is not very useful for the underlying type, but in combination with other type operators, you can use it typeof It is convenient to represent a large number of patterns.
For example, let's look at this predefined one first ReturnType<T> type.
It receives one The function type And output its return value type:

type Predicate = (x: unknown) => boolean;
type K = ReturnType<Predicate>;
//   ^?

If we want to give ReturnType Pass a function name and we'll see an indicative error:

// @errors: 2749
function f() {
  return { x: 10, y: 3 };
}
type P = ReturnType<f>;

Remember value and type It's not the same thing.
To infer f This one value target _type_We need to use it typeof

function f() {
  return { x: 10, y: 3 };
}
type P = ReturnType<typeof f>;
//   ^?

limitations

TypeScript intentionally limits what you can use typeof The kind of expression.

In particular, it is used on identifiers (that is, variable names) or their properties typeof is the only legal one.

This helps circumvent the confusing trap of writing something that you think is executed, but not executed.

// @errors: 1005
declare const msgbox: () => boolean;
// type msgbox = any;
// ---cut---
// 打算使用 = ReturnType<typeof msgbox>
let shouldContinue: typeof msgbox("Are you sure you want to continue?");
Translation of Template Literal Types.md

title: Template Literal Types
layout: docs
permalink: /zh/docs/handbook/2/template-literal-types.html

oneline: "The type of mapping of the changed property is generated by the touchpad text string."

The template text type is based on The type of string text Create, and be able to extend multiple strings by union.

They are and A template literal string in JavaScript The syntax is the same, just used to do the type.
When a specific text type is used, the template text generates a new string text type by connecting the content.

type World = "world";

type Greeting = `hello ${World}`;
//   ^?

When using unions at interpolation locations, the type is a collection of each possible string text represented by each union member:

type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";

type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
//   ^?

For each interpolated position in the template text, the set cross-multiplies:

type EmailLocaleIDs = "welcome_email" | "email_heading";
type FooterLocaleIDs = "footer_title" | "footer_sendoff";
// ---cut---
type AllLocaleIDs = `${EmailLocaleIDs | FooterLocaleIDs}_id`;
type Lang = "en" | "ja" | "pt";

type LocaleMessageIDs = `${Lang}_${AllLocaleIDs}`;
//   ^?

We generally recommend that people use large string unions that are generated in advance, but this is useful in smaller cases.

String union in type

When you want to define a new string based on an existing string, the template text is in great spirits.

For example, a common pattern in JavaScript is to extend based on existing fields on an object. We want to provide a type definition for a function that adds pairs on Support for functions that let you know when changes have been made:

// @noErrors
declare function makeWatchedObject(obj: any): any;
// ---cut---
const person = makeWatchedObject({
  firstName: "Saoirse",
  lastName: "Ronan",
  age: 26,
});

person.on("firstNameChanged", (newValue) => {
  console.log(`firstName was changed to ${newValue}!`);
});

We note on Listen is firstNameChanged event, not firstName, the template text in the type system paves the way for this string operation.

type PropEventSource<Type> = {
    on(eventName: `${string & keyof Type}Changed`, callback: (newValue: any) => void): void;
};

/// 用 'on' 方法创建一个 "watched object"
/// 这样您就可以监听属性的变化了
declare function makeWatchedObject<Type>(obj: Type): Type & PropEventSource<Type>;

With it, we can create some error content with a given error property:

// @errors: 2345
type PropEventSource<Type> = {
    on(eventName: `${string & keyof Type}Changed`, callback: (newValue: any) => void): void;
};

declare function makeWatchedObject<T>(obj: T): T & PropEventSource<T>;
// ---cut---
const person = makeWatchedObject({
  firstName: "Saoirse",
  lastName: "Ronan",
  age: 26
});

person.on("firstNameChanged", () => {});

// 可以防止打错字
person.on("firstName", () => {});

person.on("frstNameChanged", () => {});

The inference of the template text

Note that there is no type of reuse of the original value in the last example. The callback function is used any。 The template text type can be inferred from the replacement location.

We can set the last example to generic, from eventName Part of the string is extrapolated to calculate the associated property.

type PropEventSource<Type> = {
    on<Key extends string & keyof Type>
        (eventName: `${Key}Changed`, callback: (newValue: Type[Key]) => void ): void;
};

declare function makeWatchedObject<Type>(obj: Type): Type & PropEventSource<Type>;

const person = makeWatchedObject({
  firstName: "Saoirse",
  lastName: "Ronan",
  age: 26
});

person.on("firstNameChanged", newName => {
    //                        ^?
    console.log(`new name is ${newName.toUpperCase()}`);
});

person.on("ageChanged", newAge => {
    //                  ^?
    if (newAge < 0) {
        console.warn("warning! negative age");
    }
})

Here we put on becomes a generic method.

When the user passes through the string "firstNameChange" When called, TypeScript tries to infer Key the correct type.
By doing so, it will go to match in "Changed" The preceding contents are as Keyand infer that it is a string "firstName"

When TypeScript calculates this,on Method can get on the original object firstName type, where it is one string type.

Again, when used "ageChanged" Use the call, TypeScript will find out number Type age

Inferences can be made in different ways, usually by breaking down strings and then assembling them in different ways.

Built-in string action type

To aid string operations, TypeScript has a set of types used in string operations. For performance reasons, these types are built into the compiler and come with TypeScript .d.ts could not be found in .

Uppercase<StringType>

Capitalize each character in the string.

example
type Greeting = "Hello, world"
type ShoutyGreeting = Uppercase<Greeting>
//   ^?

type ASCIICacheKey<Str extends string> = `ID-${Uppercase<Str>}`
type MainID = ASCIICacheKey<"my_app">
//   ^?

Lowercase<StringType>

Lowercase each character in the string.

example
type Greeting = "Hello, world"
type QuietGreeting = Lowercase<Greeting>
//   ^?

type ASCIICacheKey<Str extends string> = `id-${Lowercase<Str>}`
type MainID = ASCIICacheKey<"MY_APP">
//   ^?

Capitalize<StringType>

Capitalize the first character in the string.

Example
type LowercaseGreeting = "hello, world";
type Greeting = Capitalize<LowercaseGreeting>;
//   ^?

Uncapitalize<StringType>

Converts the first character in the string to an equivalent lowercase character

example
type UppercaseGreeting = "HELLO WORLD";
type UncomfortableGreeting = Uncapitalize<UppercaseGreeting>;
//   ^?
内置字符操作类型的细节

从 TypeScript 4.1 开始,这些内在函数的代码直接使用 JavaScript 字符串运行时函数进行操作,并且不支持区域本地化设置。

function applyStringMapping(symbol: Symbol, str: string) {
    switch (intrinsicTypeKinds.get(symbol.escapedName as string)) {
        case IntrinsicTypeKind.Uppercase: return str.toUpperCase();
        case IntrinsicTypeKind.Lowercase: return str.toLowerCase();
        case IntrinsicTypeKind.Capitalize: return str.charAt(0).toUpperCase() + str.slice(1);
        case IntrinsicTypeKind.Uncapitalize: return str.charAt(0).toLowerCase() + str.slice(1);
    }
    return str;
}
Translation of Mapped Types.md

title: Mapped Types
layout: docs
permalink: /zh/docs/handbook/2/mapped-types.html

oneline: "Build a type by multiplexing an existing type."

When you don't want to repeat yourself, sometimes one type needs to be based on another.

The mapping type is built on the syntax of the index signature and is used to declare property types that have not been declared in advance:

type Horse = {};
// ---cut---
type OnlyBoolsAndHorses = {
  [key: string]: boolean | Horse;
};

const conforms: OnlyBoolsAndHorses = {
  del: true,
  rodney: false,
};

The mapping type is a generic type that is used PropertyKey The union of (usually Pass keyofTo iterate the key to create the type:

type OptionsFlags<Type> = {
  [Property in keyof Type]: boolean;
};

In this example,OptionsFlags reception Type All properties on the type and turn their values into boolean.

type OptionsFlags<Type> = {
  [Property in keyof Type]: boolean;
};
// ---cut---
type FeatureFlags = {
  darkMode: () => void;
  newUserProfile: () => void;
};

type FeatureOptions = OptionsFlags<FeatureFlags>;
//   ^?

Map modifiers

There are two additional modifiers that can be applied to the map:readonly and ? It acts on variability and selectivity, respectively.

You can use the prefix - to remove these modifiers, or to use + Increase them. If there is no prefix, it defaults to +

// 从类型的属性中移除 'readonly' 标记
type CreateMutable<Type> = {
  -readonly [Property in keyof Type]: Type[Property];
};

type LockedAccount = {
  readonly id: string;
  readonly name: string;
};

type UnlockedAccount = CreateMutable<LockedAccount>;
//   ^?
// 从类型的属性中移除 'optional' 标记
type Concrete<Type> = {
  [Property in keyof Type]-?: Type[Property];
};

type MaybeUser = {
  id: string;
  name?: string;
  age?: number;
};

type User = Concrete<MaybeUser>;
//   ^?

Pass as Remap the key

In TypeScript 4.1 and later, you can use the mapping type as Clause remaps keys in the mapping type:

type MappedTypeWithNewProperties<Type> = {
    [Properties in keyof Type as NewKeyType]: Type[Properties]
}

You can take advantage of it The type of template literal and other features to create a new property name from the previous property name:

type Getters<Type> = {
    [Property in keyof Type as `get${Capitalize<string & Property>}`]: () => Type[Property]
};

interface Person {
    name: string;
    age: number;
    location: string;
}

type LazyPerson = Getters<Person>;
//   ^?

You can build through conditional types never to filter out the keys:

// 移除 'kind' 属性
type RemoveKindField<Type> = {
    [Property in keyof Type as Exclude<Property, "kind">]: Type[Property]
};

interface Circle {
    kind: "circle";
    radius: number;
}

type KindlessCircle = RemoveKindField<Circle>;
//   ^?

Explore the future

The mapping type works well with other features in this type of operation section, for example, here The mapping type that uses the condition type It returns true or false, depending on whether the object will be a property pii Set to text true

type ExtractPII<Type> = {
  [Property in keyof Type]: Type[Property] extends { pii: true } ? true : false;
};

type DBFields = {
  id: { format: "incrementing" };
  name: { type: string; pii: true };
};

type ObjectsNeedingGDPRDeletion = ExtractPII<DBFields>;
//   ^?
Translation of Keyof Type Operator.md

title: Keyof Type Operator
layout: docs
permalink: /zh/docs/handbook/2/keyof-types.html

oneline: "Use the keyof keyword in the context of the type"

keyof Type operator

keyof The type operator accepts an object type that produces the character of its key or the combined type of the number:

type Point = { x: number; y: number };
type P = keyof Point;
//   ^?

If this class has one string or number Index signature, then keyof These types will be returned:

type Arrayish = { [n: number]: unknown };
type A = keyof Arrayish;
//   ^?

type Mapish = { [k: string]: boolean };
type M = keyof Mapish;
//   ^?

Note that in this example,M be string | number -- This is because the JavaScript object key is always enforced as a string, so obj[0] Always with obj[“0”] same.

keyof Types are especially useful for combining with mapping types, and we'll learn more later.

Translation of Indexed Access Types.md

title: Indexed Access Types
layout: docs
permalink: /zh/docs/handbook/2/indexed-access-types.html

oneline: "Pass Type['a'] The syntax accesses a subset of a type. "

We can use it The type of index access to find specific properties on another type.

type Person = { age: number; name: string; alive: boolean };
type Age = Person["age"];
//   ^?

The index type itself is a type, so we can use unions entirely,typeof, or any other type:

type Person = { age: number; name: string; alive: boolean };
// ---cut---
type I1 = Person["age" | "name"];
//   ^?

type I2 = Person[keyof Person];
//   ^?

type AliveOrName = "alive" | "name";
type I3 = Person[AliveOrName];
//   ^?

Try indexing a property that doesn't exist and you'll find an error:

// @errors: 2339
type Person = { age: number; name: string; alive: boolean };
// ---cut---
type I1 = Person["alve"];

Another example is to use number Go index any type to get an array of elements.
We put it with typeof Combined, the element type of the array can be easily obtained

const MyArray = [
  { name: "Alice", age: 15 },
  { name: "Bob", age: 23 },
  { name: "Eve", age: 38 },
];

type Person = typeof MyArray[number];
//   ^?
type Age = typeof MyArray[number]["age"];
//   ^?
// Or
type Age2 = Person["age"];
//   ^?

Only types can be used when indexing, which means that they cannot be used const To reference variables:

// @errors: 2538 2749
type Person = { age: number; name: string; alive: boolean };
// ---cut---
const key = "age";
type Age = Person[key];

However, you can do similar refactoring with type aliases:

type Person = { age: number; name: string; alive: boolean };
// ---cut---
type key = "age";
type Age = Person[key];
Translation of Generics.md

title: Generics
layout: docs
permalink: /zh/docs/handbook/2/generics.html

oneline: The type of receiving parameter

A major part of software engineering is building components that not only have well-defined and consistent APIs, but are also reusable.
Components that can handle both current and future data give you the flexibility to build large software systems.

One of the great tricks of creating reusable components in languages like C# and Java is Generic, that is, the ability to create components that can work on multiple types rather than a single type.
It allows users to use these components of their own type.

Generic Hello World

First, let's make a generic "hello world" with the identity function:
The identity function is a function that returns incoming content.
Think of it as similar echo The method of the command.

Without generics, we may have to give this identity The function specifies the type:

function identity(arg: number): number {
  return arg;
}

Or, we can use it any Type to represent this identity function:

function identity(arg: any): any {
  return arg;
}

Because of the use any It must be broad, which causes the function arg You can receive any and all of the types, and we don't actually know the type information of the value that the function returns.
If we pass in a number, all we can get is that it may return any type.

Instead, we need a way to know the type of argument so that we can use it to indicate what type will be returned.
Here we will use one Type variable , it is a variable that works in a type system, not a normal value.

function identity<Type>(arg: Type): Type {
  return arg;
}

We just added a type variable to the identity function Type
This one Type Allows us to capture the types of parameters passed by the user, such as number), so we'll use this information later.
Here, we use it again Type As a return type. By checking, we can now see that the parameters and return types use the same type.
This allows us to pass type information from one side of the function to the other.

We will have this version identity A function is called generic because it applies to a range of types.
with use any Unlike the first one that uses numbers as arguments and return values identity The function is as precise (e.g. it does not lose any information).

When we wrote this generic identity function, we could call it in two ways.
The first way is to pass all the parameters, including the type's arguments, to the function:

function identity<Type>(arg: Type): Type {
  return arg;
}
// ---cut---
let output = identity<string>("myString");
//       ^?

Here, we explicitly will Type Set to string, as one of the parameters of a function call, used around the argument <> represented, not used ()

The second approach is perhaps the most common. Here we use Type parameter derivation -- That is, we want the compiler to automatically set it for us by the type of parameter we pass Type The value of :

function identity<Type>(arg: Type): Type {
  return arg;
}
// ---cut---
let output = identity("myString");
//       ^?

Note that we don't have to explicitly pass the type to the single parenthesis (<>compiler will take into account "myString" and set the value of Type For its type.
Although type parameter inference is a useful tool for keeping code shorter and more readable, when the compiler cannot infer a type, you may need to explicitly pass the type parameter, as we did in the previous example, which may occur in a more complex example.

Use a common type variable

When you start using generics, you will notice when you create an image identify When such a generic function is used, the compiler forces you to use any common type parameter correctly within the function body.
That is, you can actually think of these parameters as any type.

Let's look back identity function:

function identity<Type>(arg: Type): Type {
  return arg;
}

If we want to take the arguments along with each call arg What happens when the length of is printed to the console?
Let's write this for the time being:

// @errors: 2339
function loggingIdentity<Type>(arg: Type): Type {
  console.log(arg.length);
  return arg;
}

When we write like this, the compiler will give us an error and say we are using it arg target .length members, but we didn't say that arg There is the member on it.

Keep in mind that, as we mentioned earlier, these type variables represent any and all types, so people who use this function may pass in one without .length Member's number

We say that we are actually going to use this function Type array, rather than directly using it Type。 When we are using arrays, there is a possibility .length member.
We can describe it as if we were going to create another type of array:

function loggingIdentity<Type>(arg: Type[]): Type[] {
  console.log(arg.length);
  return arg;
}

We can put it loggingIdentity The type of is understood as a "universal function." loggingIdentity Receive a type argument Type, as well as a parameter arg, the parameter is one to Type is the array type of the element, and then returns a value that is Type array.

If we pass an array of numbers, we will get an array of numbers returned because Type is bound to number

This allows us to use type variables type Being part of the type we're working on, rather than the whole type, gives us more flexibility.

We can also write an example like this:

function loggingIdentity<Type>(arg: Array<Type>): Array<Type> {
  console.log(arg.length); // Array has a .length, so no more error
  return arg;
}

This type style may seem familiar in other languages.
In the next section, we'll show you how to create an image of yourself Array<Type> Such generics.

Common type

In the previous section, we created a generic function identity, which applies to a range of types.
In this section we will explore the types of functions themselves and how to create common interfaces.

The type of a generic function is similar to that of a non-universal function, starting with a list of type parameters as if declaring a function:

function identity<Type>(arg: Type): Type {
  return arg;
}

let myIdentity: <Type>(arg: Type) => Type = identity;

We may also use different names for generic type parameters, as long as the number of type variables is consistent with the type variable actually used.

function identity<Type>(arg: Type): Type {
  return arg;
}

let myIdentity: <Input>(arg: Input) => Input = identity;

We can also write generic type signatures literally as objects:

function identity<Type>(arg: Type): Type {
  return arg;
}

let myIdentity: { <Type>(arg: Type): Type } = identity;

This let's start writing the first common interface.
Let's extract the literal amount of the object from the example above and move it to an interface:

interface GenericIdentityFn {
  <Type>(arg: Type): Type;
}

function identity<Type>(arg: Type): Type {
  return arg;
}

let myIdentity: GenericIdentityFn = identity;

In a similar example, we might want to move generic parameters to the parameters of the entire interface.

This allows us to see what type our generics are (for example,Dictionary<string> And not just Dictionary)。

This makes the type parameters visible to all other members of the interface.

interface GenericIdentityFn<Type> {
  (arg: Type): Type;
}

function identity<Type>(arg: Type): Type {
  return arg;
}

let myIdentity: GenericIdentityFn<number> = identity;

Note that we made a few changes to the example.

Instead of describing a generic function, we now have a non-universal function signature that is part of a generic type.

When we use GenericIdentityFn, we also want to specify the parameters for the corresponding type (here is:number), which effectively qualifies what the underlying call signature will use.
Understanding when to place a type argument directly on the call signature and when to place it on the interface itself will help describe which aspect of the type is generic.

In addition to common interfaces, we can also create generic classes.
Note that generic enumerations and namespaces cannot be created.

Universal class

The generic class resembles a common interface.
The parenthesis of the generic class after the class name <> there is a list of common type parameters.

// @strict: false
class GenericNumber<NumType> {
  zeroValue: NumType;
  add: (x: NumType, y: NumType) => NumType;
}

let myGenericNumber = new GenericNumber<number>();
myGenericNumber.zeroValue = 0;
myGenericNumber.add = function (x, y) {
  return x + y;
};

That's right GenericNumber A fairly literal use of a class, but you may have noticed that there is no limit to what it can only be used number type.

We can also use it string or more complex objects.

// @strict: false
class GenericNumber<NumType> {
  zeroValue: NumType;
  add: (x: NumType, y: NumType) => NumType;
}
// ---cut---
let stringNumeric = new GenericNumber<string>();
stringNumeric.zeroValue = "";
stringNumeric.add = function (x, y) {
  return x + y;
};

console.log(stringNumeric.add(stringNumeric.zeroValue, "test"));

As with interfaces, passing type parameters to the class itself ensures that all properties of the class use the same type.

Just as we are in Chapter on classes Described in , a class has two types of its types: static and instance.

Universal classes apply only to their instance aspects and do not use static aspects, so static members cannot use the type parameters of classes when using classes.

Generic restrictions

If you remember a previous example, you might sometimes want to write a generic function that works on a set of types that you know something about the functionality that the group type will have.
in our loggingIdentity In the example, we want to be able to access it arg target .length Property, but the compiler cannot prove that each type has one .length property, so it warns us not to assume that.

// @errors: 2339
function loggingIdentity<Type>(arg: Type): Type {
  console.log(arg.length);
  return arg;
}

We don't want to use any and all types, but rather to constrain the function so that it can use any and all at the same timestillNeed to have .length attribute.
As long as the type has this member, we will allow it to be used, but at least changing the membership is a must.

To do this, we must list our needs 类型 constraints of .
To do this, we'll create an interface that describes constraints.
Here we will create one with a single .length The interface of the property, and then use this interface and extends Keywords to represent our constraints:

interface Lengthwise {
  length: number;
}

function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
  console.log(arg.length); // Now we know it has a .length property, so no more error
  return arg;
}

Since the generic function is now constrained, it can no longer use any and all types:

// @errors: 2345
interface Lengthwise {
  length: number;
}

function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
  console.log(arg.length);
  return arg;
}
// ---cut---
loggingIdentity(3);

Instead, we need to pass in values whose type has all the required properties:

interface Lengthwise {
  length: number;
}

function loggingIdentity<Type extends Lengthwise>(arg: Type): Type {
  console.log(arg.length);
  return arg;
}
// ---cut---
loggingIdentity({ length: 10, value: 3 });

Use type parameters in generic constraints

You can declare type parameters that are constrained by other type parameters.

For example, here we want to get properties from objects with a given name.

We want to make sure that we don't get it accidentally obj properties that do not exist on , so we'll put a constraint between the two types:

// @errors: 2345
function getProperty<Type, Key extends keyof Type>(obj: Type, key: Key) {
  return obj[key];
}

let x = { a: 1, b: 2, c: 3, d: 4 };

getProperty(x, "a");
getProperty(x, "m");

Use the class type in generics

When you create a factory function with generics in TypeScript, you must refer to the constructor of class to the type of class. Like what

function create<Type>(c: { new (): Type }): Type {
  return new c();
}

For a further example, the prototype property is used to infer and constrain the relationship between the constructor and the instance side of the class type.

// @strict: false
class BeeKeeper {
  hasMask: boolean = true;
}

class ZooKeeper {
  nametag: string = "Mikle";
}

class Animal {
  numLegs: number = 4;
}

class Bee extends Animal {
  keeper: BeeKeeper = new BeeKeeper();
}

class Lion extends Animal {
  keeper: ZooKeeper = new ZooKeeper();
}

function createInstance<A extends Animal>(c: new () => A): A {
  return new c();
}

createInstance(Lion).keeper.nametag;
createInstance(Bee).keeper.hasMask;

This pattern benefits mixins Design mode.

Translation of Conditional Types.md

title: Conditional Types
layout: docs
permalink: /zh/docs/handbook/2/conditional-types.html

oneline: "Type like if statement in a type system"

In the most useful program, we must make a decision based on input.
JavaScript programs are no exception, but given that values can be easily introspective, these decisions are also based on the type of input.
The condition type Helps describe the relationship between input and output types.

interface Animal {
  live(): void;
}
interface Dog extends Animal {
  woof(): void;
}

type Example1 = Dog extends Animal ? number : string;
//   ^?

type Example2 = RegExp extends Animal ? number : string;
//   ^?

This form of condition type looks a bit like a conditional expression in JavaScript (condition ? trueExpression : falseExpression) :

type SomeType = any;
type OtherType = any;
type TrueType = any;
type FalseType = any;
type Stuff =
  // ---cut---
  SomeType extends OtherType ? TrueType : FalseType;

while extends The type on the left can be assigned to the right side of this is, then you will get the type on the first branch (that is, the "true" branch);

From the example above, the condition type may not become useful immediately -- we can tell ourselves Dog extensed Animal Whether it is true, then choose number or string
But the power of conditional types comes from using them with generics.

For example, let's look at the following createLabel function:

interface IdLabel {
  id: number /* some fields */;
}
interface NameLabel {
  name: string /* other fields */;
}

function createLabel(id: number): IdLabel;
function createLabel(name: string): NameLabel;
function createLabel(nameOrId: string | number): IdLabel | NameLabel;
function createLabel(nameOrId: string | number): IdLabel | NameLabel {
  throw "unimplemented";
}

createLabel These overloads of the function describe a separate JavaScript function that has different options depending on the type of input. Note these points:

  1. This can be cumbersome if a library must make the same options over and over again throughout the API.
  2. We had to create three overloads: one is the individual scenarios of the type that we have identified (one is). string The other one is number), and then the other is the most common case (receive one). string | number)。 about createLabel For each new type that can be processed, the number of overloads increases exponentially.

Instead, we can write this logic by conditional types:

interface IdLabel {
  id: number /* some fields */;
}
interface NameLabel {
  name: string /* other fields */;
}
// ---cut---
type NameOrId<T extends number | string> = T extends number
  ? IdLabel
  : NameLabel;

After that, we can use this condition type to simplify overloading to a function without overloading.

interface IdLabel {
  id: number /* some fields */;
}
interface NameLabel {
  name: string /* other fields */;
}
type NameOrId<T extends number | string> = T extends number
  ? IdLabel
  : NameLabel;
// ---cut---
function createLabel<T extends number | string>(idOrName: T): NameOrId<T> {
  throw "unimplemented";
}

let a = createLabel("typescript");
//  ^?

let b = createLabel(2.8);
//  ^?

let c = createLabel(Math.random() ? "hello" : 42);
//  ^?

Condition type constraints

Typically, the checks in the condition type give us some new information.
Just as with type protection, narrowing down can provide us with more specific types, and the true branch of the conditional type will further constrain generics through the type we are examining.

For example, let's look at the following code:

// @errors: 2536
type MessageOf<T> = T["message"];

In this example, TypeScript is reported incorrectly because T It is not possible to judge its name message The property of .
We can constrain TTypeScript no longer reports errors:

type MessageOf<T extends { message: unknown }> = T["message"];

interface Email {
  message: string;
}

type EmailMessageContents = MessageOf<Email>;
//   ^?

However, if we want to MessageOf Can accept any type, and if it does not message Property, that's a default type, just like never What should I do?

We can do this by moving constraints out and introducing condition types:

type MessageOf<T> = T extends { message: unknown } ? T["message"] : never;

interface Email {
  message: string;
}

interface Dog {
  bark(): void;
}

type EmailMessageContents = MessageOf<Email>;
//   ^?

type DogMessageContents = MessageOf<Dog>;
//   ^?

In the true branch, TypeScript understands T will Yes message attribute.

As another example, we can also write a name called Flatten The types of , flattening the array types to their element types, but not in other cases:

type Flatten<T> = T extends any[] ? T[number] : T;

// Extracts out the element type.
type Str = Flatten<string[]>;
//   ^?

// Leaves the type alone.
type Num = Flatten<number>;
//   ^?

while Flatten Receives an array type that it uses by using number Index access to get string[] The type of element of .
Otherwise, it returns only the type that was passed in to it.

Inference within the condition type

We just find ourselves using conditional types to apply constraints and then extracting types.
This is a very common operation, and the condition type makes it easier.

The condition type provides us with a way to true The method of inference in the type compared in the branch is to use infer keywords.
For example, we can infer that in Flatten The type of the element in , rather than "manually" getting it with the index access type:

type Flatten<Type> = Type extends Array<infer Item> ? Item : Type;

Here we use infer Keywords de-declaratively introduce a new generic variable Iteminstead of specifying how to go in the true branch T The element type.
This eliminates the need to consider how to explore and explore the type structures we are interested in.

wield infer Keywords, we can write some practical auxiliary type alias.
For example, for a simple scenario, we can extract a return type from a function type.

type GetReturnType<Type> = Type extends (...args: never[]) => infer Return
  ? Return
  : never;

type Num = GetReturnType<() => number>;
//   ^?

type Str = GetReturnType<(x: string) => string>;
//   ^?

type Bools = GetReturnType<(a: boolean, b: boolean) => boolean[]>;
//   ^?

When inferred from a type with multiple call signatures, such as a type of overloaded function, it is from At last Inferred from a signature, which is probably the broadest case. Overloaded resolution cannot be performed based on a list of parameter types.

declare function stringOrNum(x: string): number;
declare function stringOrNum(x: number): string;
declare function stringOrNum(x: string | number): string | number;

type T1 = ReturnType<typeof stringOrNum>;
//   ^?

The type of allocation condition

When conditional types are used on generic types, they become when a union type is given distributive
For example, look below:

type ToArray<Type> = Type extends any ? Type[] : never;

If we insert a union type ToArray, the condition type is applied to each member of the union type.

type ToArray<Type> = Type extends any ? Type[] : never;

type StrArrOrNumArr = ToArray<string | number>;
//   ^?

And then StrArrOrNumArr But this is the type of allocation:

type StrArrOrNumArr =
  // ---cut---
  string | number;

Each member type in the union type needs to be mapped in order to take effect:

type ToArray<Type> = Type extends any ? Type[] : never;
type StrArrOrNumArr =
  // ---cut---
  ToArray<string> | ToArray<number>;

It's like this:

type StrArrOrNumArr =
  // ---cut---
  string[] | number[];

In general, assignability is the expected behavior.
To avoid this behavior, you can surround each side of the extends keyword in square brackets.

type ToArrayNonDist<Type> = [Type] extends [any] ? Type[] : never;

// 'StrArrOrNumArr' 就不在是联合类型。
type StrArrOrNumArr = ToArrayNonDist<string | number>;
//   ^?
Translation of The Handbook.md

title: The TypeScript Handbook
layout: docs
permalink: /zh/docs/handbook/intro.html
oneline: First look at TypeScript

handbook: "true"

About this manual

More than 20 years after JavaScript was introduced to the programming community, it is now one of the most widely used cross-platform languages ever used. Originally a small scripting language for adding sporadic interactivity to Web pages, JavaScript is now the language of choice for front- and back-end applications of all sizes. As programs written with JavaScript grow exponentially in size, scope, and complexity, they simply do not have the ability to express correlations between different units of code. Coupled with JavaScript's unique runtime semantics, this lack of alignment between language and program complexity makes JavaScript development difficult to manage at scale.

The most typical error a programmer writes code can be called a type error: a value of a definite type is used where the expectation is that it is another type of value. This could be a simple typo, a misunderstanding of the library's outer API, an improper guess about runtime behavior, or something else. TypeScript is designed to be a static type checker for JavaScript programs - in other words, a tool (type checked) that runs before your code runs (static) to ensure that the program's type is correct.

If you approached TypeScript without JavaScript in an attempt to make TypeScript your first development language, we recommend that you read these documents first Microsoft Learn JavaScript tutorial or JavaScript at the Mozilla Web Docs
If you have development experience in other languages, you should be able to master JavaScript syntax very quickly by reading this manual

The structure of this operating manual

This operating manual is divided into two sections:

  • handbook

    The TypeScript manual is intended as a comprehensive document to explain TypeScript to everyday programmers. You can read the manual from top to bottom in the left navigation bar.

    You should expect that each chapter or page will give you a deep understanding of a given concept. The TypeScript manual is not a complete language specification, but it is designed to provide comprehensive guidance on all the characteristics and behaviors of the language.

    Readers who have completed the walkthrough should be able to:

    • Read and understand common TypeScript syntax and patterns
    • Explains the effect of important compiler options
    • In most cases, the type system behavior is correctly predicted

    For clarity and brevity, the main content of this manual does not address every edge situation or detail of the features covered. You can find more details about specific concepts in the reference article.

  • Reference file

    The reference section below the manual in the navigation is designed to provide a deeper understanding of how specific parts of TypeScript work. You can read from the top down, but the purpose of each section is to explain a concept in greater depth -- which means that there is no continuous goal.

Non-target

The manual is also a concise document that can be easily read in a matter of hours. To keep it short, some topics will not be covered.

Specifically, the manual does not fully cover the core JavaScript basics, such as functions, classes, and closures. Where appropriate, we will include background reading links that you can use to read these concepts.

This manual is also not intended to replace language specifications. In some cases, a formal description of an edge case or behavior is skipped to support a higher level of understanding. Instead, there are separate reference pages that describe many aspects of TypeScript behavior more precisely and formally. Reference pages are not intended for readers who are not familiar with TypeScript, so they may use advanced terms or reference topics that you have not read.

Finally, this manual does not describe how TypeScript interacts with other tools, except where necessary. Topics such as how to configure TypeScript using webpack, rollup, packet, react, babel, closure, lerna, rush, bazel, preact, vue, angular, svelte, jquery, warn, or npm are beyond the scope of the discussion - you can find these resources elsewhere on the web.

Entry

At the beginning of learning[Basics]Before (/docs/handbook/2/basic types .html), we recommend reading one of the following introductory pages. These presentations are intended to highlight the key similarities and differences between TypeScript and your favorite programming languages and to clarify common misconceptions that are specific to these languages.

Otherwise jump to The Basics Or inEpub Get a copy or PDF form.

Generated by 🚫 dangerJS against bb113be

@Kingwl
Copy link
Contributor

Kingwl commented Sep 13, 2021

Thanks for the contribution. I'll start review in few days.

@zhouLion zhouLion closed this Jul 7, 2023
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.

None yet

2 participants