一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第26天,点击查看活动详情。
题目四十二:omitbytype
// template.ts
type OmitByType<T, U> = any
// test-cases.ts
import type { Equal, Expect } from '@type-challenges/utils'
interface Model {
name: string
count: number
isReadonly: boolean
isEnable: boolean
}
type cases = [
Expect<Equal<OmitByType<Model, boolean>, { name: string; count: number }>>,
Expect<Equal<OmitByType<Model, string>, { count: number; isReadonly: boolean; isEnable: boolean }>>,
Expect<Equal<OmitByType<Model, number>, { name: string; isReadonly: boolean; isEnable: boolean }>>,
]
从 T 中,选择一组类型不可分配给 U 的属性。
测试用例
OmitByType<Model, boolean>
从 Model 中,去除值为 boolean 的内容,期望结果是:{ name: string; count: number; }
OmitByType<Model, string>
从 Model 中,去除值为 string 的内容,期望结果是:{ count: number; isReadonly: boolean; isEnable: boolean }
OmitByType<Model, number>
从 Model 中,去除值为 number 的内容,期望结果是:{ name: string; isReadonly: boolean; isEnable: boolean }
代码实现
- 原代码
type OmitByType<T, U> = any
- 对
T进行遍历
type OmitByType<T, U> = {
[P in keyof T]: T[P]
}
- 将当前遍历项的
key转换为never或P
在转换之前判断一下 T[P] 是否 extends U
type OmitByType<T, U> = {
[P in keyof T as T[P] extends U ? never : P]: T[P]
}
题目四十三:objectentries
// template.ts
type ObjectEntries<T> = any
// test-cases.ts
import type { Equal, Expect } from '@type-challenges/utils'
interface Model {
name: string
age: number
locations: string[] | null
}
type ModelEntries = ['name', string] | ['age', number] | ['locations', string[] | null]
type cases = [
Expect<Equal<ObjectEntries<Model>, ModelEntries>>,
Expect<Equal<ObjectEntries<Partial<Model>>, ModelEntries>>,
Expect<Equal<ObjectEntries<{ key?: undefined }>, ['key', undefined]>>,
Expect<Equal<ObjectEntries<{ key: undefined }>, ['key', undefined]>>,
]
实现 TS 类型版的 Object.entries
测试用例
ObjectEntries<Model>
将 Model 的内容转换为:[key, value] | [key, value] 的形式
Partial<Model>
对可选值也不影响,视为不可选一样的效果
ObjectEntries<{ key?: undefined }>
undefined 也不影响,直接让值为 undefined
代码实现
- 原代码
type ObjectEntries<T> = any
- 对
T进行遍历
type ObjectEntries<T> = {
[P in keyof T]: T[P]
}
- 将值修改为
[key, value]的形式
type ObjectEntries<T> = {
[P in keyof T]: [P, T[P]]
}
- 将整体转换为联合类型(
obj[key]) 进行访问
type ObjectEntries<T> = {
[P in keyof T]: [P, T[P]]
}[keyof T]
这时虽然整体实现了,但是会发现可选参数变成了 [name, string | undefined],但是我们期望的是 [name, string]
所以这个实现方式不可取
代码实现2
- 原代码
type ObjectEntries<T> = any
- 手动进行遍历,先拿出
T的键数组
type ObjectEntries<T> = keyof T
- 使用
extends对keyof T进行逐个遍历,遍历项定义为P
type ObjectEntries<T> = keyof T extends infer P
? ...
: never
- 上面是遍历
T,从T中拿出P;接下来以P为主体进行判断
type ObjectEntries<T> = keyof T extends infer P
? P extends keyof T // 这样才能在下一层中使用 P
? ...
: never
: never
- 组装成数组
type ObjectEntries<T> = keyof T extends infer P
? P extends keyof T // 这样才能在下一层中使用 P
? [P, T[P]]
: never
: never
- 如果
T[P]是可选的话,去除undefined
type ObjectEntries<T> = keyof T extends infer P
? P extends keyof T
? [P, T[P] extends infer R | undefined
? R
: T[P]]
: never
: never