-
Notifications
You must be signed in to change notification settings - Fork 130
Translate _Type Manipulation_ Into Chinese #120
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
Conversation
zhouLion
commented
Sep 12, 2021
- Markdown Files: documents of Type Manipulation of handbook-v2
- Language: Chinese
TODO: to translate these
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. |
Translation of Angular.mdtitle: Angular deprecated: trueAngular 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.mdtitle: Type Checking JavaScript Files oneline: How to add type checks to JavaScript files using TypeScriptand The property is inferred from the assignment in the body of the classES2015 has no way to declare its properties within a class. Properties are dynamically assigned, just like the literal amount of an object. at // @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. // @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 classesPrior to ES2015, JavaScript used constructor functions instead of classes. // @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 supportedin one // 等同 `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. Types, functions, and object literals are namespacesat 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 openOne 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 // @checkJs
// @errors: 2339
/** @type {{a: number}} */
var obj = { a: 1 };
obj.b = 2; The null, undefined, and empty arrays are initialized to any or anyAny variable, argument, or property, once initialized as 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 defaultBecause there was no way to make parameters optional in JavaScript prior to ES2015, it was not available 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. /**
* @param {string} [somebody] - Somebody's name.
*/
function sayHello(somebody) {
if (!somebody) {
somebody = "John Doe";
}
console.log("Hello " + somebody);
}
sayHello(); Used
|
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.
- Generic - The type of receiving parameter
- Keyof type operator - Pass
keyof
The operator creates a new type - Typeof type operator - Pass
typeof
The operator creates a new type - Access type by index - Pass
Type['a']
The syntax accesses a subset of a type - The condition type - Type in a type system like an if statement
- The type of mapping - Create a type from a property map of an existing type
- The type of template literal - The type has been mapped, which changes its properties through the template literally string
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 typeof
to 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 Key
and 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 keyof
To 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:
- This can be cumbersome if a library must make the same options over and over again throughout the API.
- We had to create three overloads: one is the individual scenarios of the type that we have identified (one is).
string
The other one isnumber
), and then the other is the most common case (receive one).string | number
)。 aboutcreateLabel
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 T
TypeScript 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 Item
instead 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.
- TypeScript for New Programmers
- TypeScript for JavaScript Programmers
- TypeScript for OOP Programmers
- TypeScript for Functional Programmers
Otherwise jump to The Basics Or inEpub Get a copy or PDF form.
Thanks for the contribution. I'll start review in few days. |