ts类型挑战【二十四】

229 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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 转换为 neverP

在转换之前判断一下 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
  • 使用 extendskeyof 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