获取通用接口扩展

Get generic interface extension

考虑以下接口:

interface A {
   name: string;
   value: number;
   sub: {
       query: number[]
   },
   old: number;
}

interface B {
   name: string;
   value: string;
   sub: {
       query: string[]
   },
   new: boolean;
}

我正在寻找通用解决方案来获得 interface/type:

interface C extends B, A {
}

其中 C 类似于接口 D:

interface D {
   name: string;
   value: string;
   sub: {
       query: string[]
   },
   old: number;
   new: boolean;
}

所以我可以有一个功能:

function merge<T, U>(t: T, u: U): interface C extends T, U {
  // Merge objects
  // ...
  return obj;
}

它不一定是一个接口。 A 类型也可以(我认为)。

类型 A & B 不起作用,因为那时我有一个交集(例如 value 将是 number & string 类型)。

我使用这个 MergeReplace 类型来更准确地输入 Object.assign({}, T, S):

type MergeReplace<T, S> = Omit<T, keyof T & keyof S> & S;
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;

如果您使用的是 < 2.8 的 TypeScript,Exclude 可以这样定义:

type Project<K extends string, T> = (T & {[x: string]: never})[K];
type Delete<T extends string, U extends string> = ({[P in T]: P} & {[P in U]: never});
type Exclude<T extends string, U extends string> = Project<T, Delete<T,U>>;

TypeScript playground with examples

注意 MergeReplace 是右偏的,所以如果 TS 共享一个 属性 但类型不同,则 S 的类型是已选择。

查看 this TypeScript issue 了解更多信息。

我想我明白了:

type MergeRightBiased<TLeft, TRight> =
  TLeft extends any[] ? TRight :
    TRight extends any[] ? TRight :
      TLeft extends object ?
        TRight extends object ? {
          // All properties of Left and Right, recursive
          [P in keyof TLeft & keyof TRight]: MergeRightBiased<TLeft[P], TRight[P]>
        } & {
          // All properties of Left not in Right
          [P in Exclude<keyof TLeft, keyof TRight>]: TLeft[P];
        } & {
          // All properties of Right not in Left
          [P in Exclude<keyof TRight, keyof TLeft>]: TRight[P]
        }
          // Prefer Right
          : TRight
        : TRight;

感谢@Oblosys 的帮助!