持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第 4 天
如何使用映射类型 in
type Person = {id?: number, name: string, age: number}
type Readonly<T> = {
readonly [K in keyof T]: T[K]
}
type X1 = Readonly<Person>
// 重名了,谁离我近我就用哪个,这里叫做覆盖,如果我写了 TS 默认写的那个就没有用了
type Partial<T> = {
[K in keyof T] ?: T[K]
}
// 假设 Person 有个 id, 有时候我们做不了 id
// 很多时候在做表单创建的时候,id 做不了,等到我保存成功才有
type X2 = Partial<Person>
// -? 把 id? 变成了必须选的
type Required<T> = {
[k in keyof T]-?: T[k]
}
type X3 = Required<Person>
// 以下 O 和 O2 等价
type O = {
[index: string]: number
}
type O2 = Record<string, number>
type Record<Key extends string | number | symbol, Value> = {
[k in Key]: Value
}
type X4 = Record<string, number>
这里为什么会出现 string | number
// 1. 因为 JS 程序员说 我的 key 可以是 number, 所以这个 冒号 : 有做特殊处理
type Y = {
// 4. 所以这里没有 一一对应
/* 5. 所以这个冒号在用泛型的时候,就会遇到一些问题,
本来是一个简单的 string 类型,它会变成一个并集,
那你变成一个并集之后,是会走分配律的,
就导致整个 TS 的类型可能会遇到一些不能预测的 bug */
[k: string]: number
}
// 6. 所以需要发明一种新的语法
type Z = {
[k in string]: number
}
type YK = keyof Y // string | number
type ZK = keyof Z // srting
const obj = {
1 : 'one',
2 : 'two'
}
const n = 1
obj[n]
// 2. 所以对于 JS 程序员来说这个下标就可以是 number,虽然根本不存在于有一个 number 的 number 下标
// 3. TS 程序员为了兼容 JS 的习惯,你说你是 string 的时候,我觉得你可能是 number | string
// 因为分配律,这里是 A 里面的每一个元素是否包含于 b
// 如果在里面我就不要
type Exclude<A, B> = A extends B ? never : A
type X5 = Exclude<1 | 2 | 3, 1 | 2> // 3
// 使用代入法推演过程
type X5 = 1 | 2 | 3 extends 1 | 2 ? never : 3
type X5 =
| 1 extends 1 | 2 ? never : 1 // never
| 2 extends 1 | 2 ? never : 2 // never
| 3 extends 1 | 2 ? never : 3 // 3
// type X5 = never | never | 3
type X5 = 3
// A 里面的每一个元素是否包含于 B , 如果在里面我就要
type Extract<A, B> = A extends B ? A : never
type X6 = Extract<1 | 2 | 3, 2 | 4> // 2
type Person = {id?: number, name: string, age: number}
// Omit 的意思是 我需要忽略掉这个对象的两个 key
type Omit<T, Key> = {
[k in keyof T as k extends Key ? never : k] : T
}
type X7 = Omit<Person, 'name' | 'age'>
这里的 as 可以强制断言,改写你的值,就很像赋值。
看一哈 TS 内置的 Omit
使用到了 Pick
它是一个映射类型
// 模拟一下 Pick
type Person = {id?: number, name: string, age: number}
type Pick<T, Key extends keyof T> = {
[k in Key]: T[Key]
}
type X8 = Pick<Person, 'name' | 'age'>
X8 正好获取到 name、age 不要 id
说明 Pick 映射到 key 是后面的集合。
有了 Pick 在写 Omit
type Person = {id?: number, name: string, age: number}
type Exclude<A, B> = A extends B ? never : A
type X5 = Exclude<1 | 2 | 3, 1 | 2>
type Omit<T, Key extends keyof T> = Pick<T, Exclude<keyof T, Key>>
type X7 = Omit<Person, 'name' | 'age'>
type Pick<T, Key extends keyof T> = {
[k in Key]: T[Key]
}
type X8 = Pick<Person, 'name' | 'age'>
如何使用 -readonly
readonly 是把一个对象的属性变成可读的,那么如何把一个对象的属性变成可写的。
// 这里该如何填?
type Mutable<Type> = {
?????? [Property in keyof Type]: Type[Property]
}
type Y = Mutable<Readonly<Person>> // 如何用 Mutable 变成全可写的?
type Person = {
readonly id: number
readonly name: string
readonly age: number
}
// 使用 -readonly 把可读的变成可写的
type Mutable<T> = {
-readonly [K in keyof T]: T[K]
}
type X9 = Mutable<Person>
就全都没有 readonly
总结
从类型中创造类型:
extends包含于keyof获取到一个对象的所有 key,把它 key 变成一个并集T['name']T 是一个类型,然后它的下标是可以直接传一个字符串,如果是一个泛型可以传一个 key,这个 key 就必须是 keyof key。[K in keyof T]- Mapped Types 映射类型
in keyof- readonly[][] --readonly [K in keyof T] -?: [K]前面能减 readonly, 后面[]-表示可选
as断言
如何学习泛型
- 别用 any
- 做题:🔗
- 与别人交流
如下图所示如何做题和解答
文章分享: