[TypeScript] Type Challenges #645 - Diff

59 阅读2分钟

题目描述

获取两个接口类型中的差值属性。

type Foo = {
  a: string;
  b: number;
}
type Bar = {
  a: string;
  c: boolean
}

type Result1 = Diff<Foo,Bar> // { b: number, c: boolean }
type Result2 = Diff<Bar,Foo> // { b: number, c: boolean }

题解

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

type Foo = {
  name: string
  age: string
}
type Bar = {
  name: string
  age: string
  gender: number
}
type Coo = {
  name: string
  gender: number
}

type cases = [
  Expect<Equal<Diff<Foo, Bar>, { gender: number }>>,
  Expect<Equal<Diff<Bar, Foo>, { gender: number }>>,
  Expect<Equal<Diff<Foo, Coo>, { age: string; gender: number }>>,
  Expect<Equal<Diff<Coo, Foo>, { age: string; gender: number }>>,
]


// ============= Your Code Here =============
type Diff0<L, R> = Omit<L & R, keyof (L | R)>

type Diff1<L, R> = {
  [P in keyof L | keyof R
      as Exclude<P, keyof (L | R)>
  ]:
      P extends keyof L
          ? L[P]
          : P extends keyof R
              ? R[P]
              : never
}

type Diff<L, R> = {
  [P in keyof L | keyof R
      as P extends L
          ? P extends R
              ? never 
              : P 
          : P
  ]:
      P extends keyof L
          ? L[P]
          : P extends keyof R
              ? R[P]
              : never
}

题解1:使用Omit和联合类型

type Diff0<L, R> = Omit<L & R, keyof (L | R)>
  • 联合类型L | R

    • L | RLR的联合类型,表示一个类型可以是LR

    • keyof (L | R)会提取LR中所有键的并集

  • 交叉类型L & R

    • L & RLR的交叉类型,表示一个类型同时具有LR的所有属性
  • Omit类型:

    • Omit<T, K>是一个内置类型工具,它会从类型T中排除键K

    • Omit<L & R, keyof (L | R)>会从L & R中排除LR的所有键的并集

题解2:使用条件类型和Exclude

type Diff1<L, R> = {
  [P in keyof L | keyof R
      as Exclude<P, keyof (L | R)>
  ]:
      P extends keyof L
          ? L[P]
          : P extends keyof R
              ? R[P]
              : never
}
  • 遍历联合类型:

    • [P in keyof L | keyof R]:遍历LR的所有键的联合类型
  • 条件映射:

    • as Exclude<P, keyof (L | R)>:排除LR的所有键的并集

  • 条件赋值:

    • P extends keyof L ? L[P] : P extends keyof R ? R[P] : never

      • 如果PL的键,则返回L[P]

      • 如果PR的键,则返回R[P]

      • 否则,返回never

题解3:使用条件类型和never

type Diff<L, R> = {
  [P in keyof L | keyof R
      as P extends L
          ? P extends R
              ? never 
              : P 
          : P
  ]:
      P extends keyof L
          ? L[P]
          : P extends keyof R
              ? R[P]
              : never
}
  • 遍历联合类型:

    • [P in keyof L | keyof R]:遍历LR的所有键的联合类型
  • 条件映射:

    • as P extends L ? P extends R ? never : P : P

      • 如果PL的键,并且P也是R的键,则将P映射为never(即排除公共键)

      • 否则,保留P

  • 条件赋值:

    • P extends keyof L ? L[P] : P extends keyof R ? R[P] : never

      • 如果PL的键,则返回L[P]

      • 如果PR的键,则返回R[P]

      • 否则,返回never