[TypeScript] Type Challenges #3- Omit

72 阅读1分钟

题目描述

不使用 Omit 实现 TypeScript 的 Omit<T, K> 泛型。

Omit 会创建一个省略 K 中字段的 T 对象。

例如:

interface Todo {
  title: string
  description: string
  completed: boolean
}

type TodoPreview = MyOmit<Todo, 'description' | 'title'>

const todo: TodoPreview = {
  completed: false,
}

题解

// ============= Test Cases =============
import type { Equal, Expect } from './test-utils'

type cases = [
  Expect<Equal<Expected1, MyOmit<Todo, 'description'>>>,
  Expect<Equal<Expected2, MyOmit<Todo, 'description' | 'completed'>>>,
]

// @ts-expect-error
type error = MyOmit<Todo, 'description' | 'invalid'>

interface Todo {
  title: string
  description: string
  completed: boolean
}

interface Expected1 {
  title: string
  completed: boolean
}

interface Expected2 {
  title: string
}


// ============= Your Code Here =============
type MyOmit<T, K extends keyof T> = {
  [U in keyof T as U extends K ? never : U]: T[U]
}

首先,使用K extends keyof T对类型参数K进行约束,确保K仅包含对象类型T的键,防止传入T中不存在的键

通过[U in keyof T]遍历T的键,将每个键存储在U

接着,使用as关键字重新映射键。通过条件判断U extends K ? never : U来处理每个键:

  • 如果U属于要排除的键集合K,将该键值映射为never,以此来排除该键,never类型表示该键不会出现在最终的对象类型中

  • 如果U不属于K,则保留该键及原始类型