[Typescript Challenges] 147 Medium - MergeAll

发布时间 2023-07-17 02:40:13作者: Zhentiw

Merge variadic number of types into a new type. If the keys overlap, its values should be merged into an union.

For example:

type Foo = { a: 1; b: 2 }
type Bar = { a: 2 }
type Baz = { c: 3 }

type Result = MergeAll<[Foo, Bar, Baz]> // expected to be { a: 1 | 2; b: 2; c: 3 }

 

Answer:

/* _____________ Your Code Here _____________ */
export type MergeValueAsUnion<
  F extends object,
  S extends object
> = {
  [Key in  (keyof F | keyof S)]: Key extends keyof S 
    ? S[Key] | (Key extends keyof F ? F[Key] : never)
    : Key extends keyof F
      ? F[Key]
      : never
};
type MergeAll<XS extends object[], ACC extends object = {}> = XS extends [infer A extends object, ...infer REST extends object[]]
  ? MergeAll<REST, MergeValueAsUnion<ACC, A>>
  : ACC;

/* _____________ Test Cases _____________ */
import type { Equal, Expect } from '@type-challenges/utils'

type cases = [
  Expect<Equal<MergeAll<[]>, {} >>,
  Expect<Equal<MergeAll<[{ a: 1 }]>, { a: 1 }>>,
  Expect<Equal<
    MergeAll<[{ a: string }, { a: string }]>,
    { a: string }>
  >,
  Expect<Equal<
    MergeAll<[{ }, { a: string }]>,
    { a: string }>
  >,
  Expect<Equal<
    MergeAll<[{ a: 1 }, { c: 2 }]>,
    { a: 1; c: 2 }>
  >,
  Expect<Equal<
    MergeAll<[{ a: 1; b: 2 }, { a: 2 }, { c: 3 }]>,
    { a: 1 | 2; b: 2; c: 3 }>
  >,
  Expect<Equal<MergeAll<[{ a: 1 }, { a: number }]>, { a: number }>>,
  Expect<Equal<MergeAll<[{ a: number }, { a: 1 }]>, { a: number }>>,
  Expect<Equal<MergeAll<[{ a: 1 | 2 }, { a: 1 | 3 }]>, { a: 1 | 2 | 3 }>>,
]