diff --git a/chapters.yml b/chapters.yml index 8012b7e..3fc9cf7 100644 --- a/chapters.yml +++ b/chapters.yml @@ -13,3 +13,5 @@ - enum.md: Enum 类型 - assert.md: 类型断言 - operator.md: 运算符 +- mapping.md: 类型映射 +- utility.md: 类型工具 diff --git a/docs/mapping.md b/docs/mapping.md index e4350af..8cf9bb2 100644 --- a/docs/mapping.md +++ b/docs/mapping.md @@ -18,7 +18,7 @@ type B = { }; ``` -上面示例中,这两个类型的属性结构是一样的,但是属性的类型不一样。如果属性数量多的话,写起来就很麻烦。 +上面示例中,这两个类型的属性结构是一样的,但是属性的类型不一样。如果属性数量多的话,逐个写起来就很麻烦。 使用类型映射,就可以从类型`A`得到类型`B`。 @@ -66,8 +66,6 @@ type ToBoolean = { 上面示例中,定义了一个泛型,可以将其他对象的所有属性值都改成 boolean 类型。 -由于对象的属性名,只有 string、number、symbol 三种可能,所以 keyof 运算符返回的联合类型,应该是`string | number | symbol`的子类型。 - 下面是另一个例子。 ```typescript @@ -145,12 +143,12 @@ type Readonly = { ```typescript type T = { a: string; b: number }; - -// { + +type ReadonlyT = Readonly; +// { // readonly a: string; // readonly b: number; // } -type ReadonlyT = Readonly; ``` ## 映射修饰符 @@ -178,7 +176,7 @@ type B = { 如果要删改可选和只读这两个特性,并不是很方便。为了解决这个问题,TypeScript 引入了两个映射修饰符,用来在映射时添加或移除某个属性的`?`修饰符和`readonly`修饰符。 -- `+`修饰符:写成`+?`或`+readonly`,为映射属性添加`?`修饰符或`readonly`修饰符。 +- `+`修饰符:写成`+?`或`+readonly`,为映射属性添加`?`修饰符或`readonly`修饰符。 - `–`修饰符:写成`-?`或`-readonly`,为映射属性移除`?`修饰符或`readonly`修饰符。 下面是添加或移除可选属性的例子。 @@ -248,7 +246,7 @@ type B = { ### 语法 -TypeScript 4.1 引入了键名重映射(key remapping),允许将键名指定为其他类型。 +TypeScript 4.1 引入了键名重映射(key remapping),允许改变键名。 ```typescript type A = { @@ -281,12 +279,12 @@ interface Person { } type Getters = { - [P in keyof T - as `get${Capitalize}`]: () => T[P]; + [P in keyof T + as `get${Capitalize}`]: () => T[P]; }; - + type LazyPerson = Getters; -// 等同于 +// 等同于 type LazyPerson = { getName: () => string; getAge: () => number; @@ -313,20 +311,20 @@ type User = { } type Filter = { - [K in keyof T - as T[K] extends string ? K : never]: string + [K in keyof T + as T[K] extends string ? K : never]: string } type FilteredUser = Filter // { name: string } ``` -上面示例中,映射`K in keyof T`获取类型`T`的每一个属性以后,然后使用`as Type`修改键名的类型。 +上面示例中,映射`K in keyof T`获取类型`T`的每一个属性以后,然后使用`as Type`修改键名。 -它的键盘重映射`as T[K] extends string ? K : never]`,使用了条件运算符。如果属性值`T[K]`的类型是字符串,那么属性名不变,否则属性名类型改为`never`,即这个属性名不存在。这样就等于过滤了不符合条件的属性,只保留属性值为字符串的属性。 +它的键名重映射`as T[K] extends string ? K : never]`,使用了条件运算符。如果属性值`T[K]`的类型是字符串,那么属性名不变,否则属性名类型改为`never`,即这个属性名不存在。这样就等于过滤了不符合条件的属性,只保留属性值为字符串的属性。 ### 联合类型的映射 -由于键名重映射可以修改键名类型,所以原始键名的类型不必是`string|number|symbol`,任意的联合类型都可以。 +由于键名重映射可以修改键名类型,所以原始键名的类型不必是`string|number|symbol`,任意的联合类型都可以用来进行键名重映射。 ```typescript type S = { @@ -340,7 +338,7 @@ type C = { radius: number, }; -type MyEvents = { +type MyEvents = { [E in Events as E['kind']]: (event: E) => void; } @@ -357,3 +355,4 @@ type Config = { ## 参考链接 - [Mapped Type Modifiers in TypeScript](https://mariusschulz.com/blog/mapped-type-modifiers-in-typescript), Marius Schulz + diff --git a/docs/utility.md b/docs/utility.md index 005302e..7168ef2 100644 --- a/docs/utility.md +++ b/docs/utility.md @@ -34,7 +34,7 @@ type C = Awaited>; `Awaited`的实现如下。 ```typescript -type Awaited = +type Awaited = T extends null | undefined ? T : T extends object & { then( @@ -56,7 +56,7 @@ type Awaited = type T1 = ConstructorParameters< new (x: string, y: number) => object >; // [x: string, y: number] - + type T2 = ConstructorParameters< new (x?: string) => object >; // [x?: string | undefined] @@ -88,7 +88,7 @@ type T2 = ConstructorParameters; // 报错 `any`类型和`never`类型是两个特殊值,分别返回`unknown[]`和`never`。 -```typescript +```typescript type T1 = ConstructorParameters; // unknown[] type T2 = ConstructorParameters; // never @@ -262,12 +262,14 @@ function toHex(this: Number) { type T = OmitThisParameter; // () => string ``` +上面示例中,`OmitThisParameter`给出了函数`toHex()`的类型,并将其中的`this`参数删除。 + 如果函数没有 this 参数,则返回原始函数类型。 `OmitThisParameter`的实现如下。 ```typescript -type OmitThisParameter = +type OmitThisParameter = unknown extends ThisParameterType ? T : T extends (...args: infer A) => infer R ? (...args: A) => R : T; @@ -281,7 +283,7 @@ type OmitThisParameter = type T1 = Parameters<() => string>; // [] type T2 = Parameters<(s:string) => void>; // [s:string] - + type T3 = Parameters<(arg: T) => T>; // [arg: unknown] type T4 = Parameters< @@ -459,7 +461,7 @@ interface Person { age: number; } -const worker: Readonly> +const worker: Readonly> = { name: '张三' }; worker.name = '李四'; // 报错 @@ -605,7 +607,7 @@ type T2 = ReturnType; // never ```typescript type ReturnType< T extends (...args: any) => any -> = +> = T extends (...args: any) => infer R ? R : any; ``` @@ -644,7 +646,7 @@ interface HelperThisValue { let helperFunctions: { [name: string]: Function } & - ThisType + ThisType = { hello: function() { this.logError("Error: Something wrong!"); // 正确 @@ -662,7 +664,7 @@ let helperFunctions: 下面是另一个例子。 ```typescript -let obj: ThisType<{ x: number }> & +let obj: ThisType<{ x: number }> & { getX: () => number }; obj = { @@ -734,10 +736,11 @@ type A = 'HELLO'; // "hELLO" type B = Uncapitalize; -``` +``` 上面示例中,`Uncapitalize`将 HELLO 转为 hELLO。 ## 参考链接 - [What is TypeScript's ThisType used for?](https://stackoverflow.com/questions/55029032/what-is-typescripts-thistype-used-for) +