如何实现实用程序类型以将接口合并为一个具有 Object.assign 逻辑的接口?

Ora*_*bot 5 typescript typescript-generics

我需要一种实用程序类型,可以将传递的联合中的两个或多个接口合并为一个,而不需要解决重复的 props 而是never覆盖。它应该像 Object.assign 一样工作,但适用于类型/接口。假设我们有三种类型:

    type A = {a: number};
    type B = {a: boolean, b: boolean};
    type C = {c: boolean};
Run Code Online (Sandbox Code Playgroud)

我想要一些实用程序可以将它们合并为一个:

type MergedType = MergeTypes<A|B|C>;
Run Code Online (Sandbox Code Playgroud)

在结果中我想得到以下界面:

type MergedType = {
  a: boolean, // overwriting, not `never` in case of using intersection (A & B & C)
  b: boolean,
  c: boolean
}
Run Code Online (Sandbox Code Playgroud)

有什么解决方案可以达到这种行为吗?我只能为具有单独泛型参数的两个接口编写实用程序

  type MergeTypes<S, T> = Omit<S, keyof T> & T;

  type MergedType = MergeTypes<A, B>;
Run Code Online (Sandbox Code Playgroud)

但我不知道如何参考前面的参数迭代联合以达到数组归约逻辑。先感谢您!

Dim*_*ava 1

type Pure<T> = { [K in keyof T]: T[K] } & unknown
type Check<T, Eq extends ([T, V] extends [V, T] ? '=' : '!='), V> = T

type Assign<T, U> = Pure<Omit<T, keyof U> & U>
type AssignList<A extends any[]> =
  | A extends [infer F] ? F
  : A extends [...infer F, infer L] ? Assign<AssignList<F>, L>
  : never

type checkAssignList = {
  case1: Check<AssignList<[{ a: 1 }]>, '=', { a: 1 }>,
  // ^?
  case2: Check<AssignList<[{ a: 1 }, { a: 2 }]>, '=', { a: 2 }>,
  // ^?
  case3: Check<AssignList<[{ a: 1 }, { a: 2 }, { a: 3 }]>, '=', { a: 3 }>,
  // ^?
  case4: Check<AssignList<[{ a: 1 }, { b: 2 }, { a: 3 }]>, '=', { a: 3, b: 2 }>,
  // ^?
}

const assign = Object.assign as <T extends {}, A extends readonly any[]>(target: T, ...sources: A) => AssignList<[T, ...A]>

const checkAssignList = {
  case1: assign({ a: 1 }),
  // ^?
  case2: assign({ a: 1 }, { a: 2 }),
  // ^?
  case3: assign({ a: 1 }, { a: 2 }, { a: 3 }),
  // ^?
  case4: assign({ a: 1 }, { b: 2 }, { a: 3 }),
  // ^?
}
console.log(checkAssignList)
Run Code Online (Sandbox Code Playgroud)