[TypeScript] Type Challenges #2757 - PartialByKeys

14 阅读1分钟

题目描述

实现一个通用的PartialByKeys<T, K>,它接收两个类型参数TK

K指定应设置为可选的T的属性集。当没有提供K时,它就和普通的Partial<T>一样使所有属性都是可选的。

例如:

interface User {
  name: string
  age: number
  address: string
}

type UserPartialName = PartialByKeys<User, 'name'> // { name?:string; age:number; address:string }

题解

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

interface User {
  name: string
  age: number
  address: string
}

interface UserPartialName {
  name?: string
  age: number
  address: string
}

interface UserPartialNameAndAge {
  name?: string
  age?: number
  address: string
}

type cases = [
  Expect<Equal<PartialByKeys<User, 'name'>, UserPartialName>>,
  Expect<Equal<PartialByKeys<User, 'name' | 'age'>, UserPartialNameAndAge>>,
  Expect<Equal<PartialByKeys<User>, Partial<User>>>,
  // @ts-expect-error
  Expect<Equal<PartialByKeys<User, 'name' | 'unknown'>, UserPartialName>>,
]


// ============= Your Code Here =============
type MergeIntersection<T> = {
  [P in keyof T]: T[P]
}

type PartialByKeys<
  T,
  K extends keyof T = keyof T
> =
  MergeIntersection<
    & Omit<T, K> 
    & Partial<Pick<T, K>>
  >

类型操作

  1. MergeIntersection<T>

    • 这个类型的作用是将一个交叉类型中的所有属性合并成一个单一的类型

    • { [P in keyof T]: T[P] }:遍历T的所有键,将每个键的值类型提取出来,形成一个新的类型

  2. PartialByKeys<T, K>

    • K extends keyof T = keyof TK是一个联合类型,表示要使哪些属性变为可选。如果没有提供K,则默认为keyof T,即所有属性都变为可选

    • Omit<T, K>:从T中排除K指定的属性

    • Partial<Pick<T, K>>:将T中的K指定的属性变为可选

    • Omit<T, K> & Partial<Pick<T, K>>:将排除的属性和变为可选的属性合并

    • MergeIntersection<...>:将合并后的交叉类型中的所有属性合并成一个单一的类型