Search code examples
typescripttypesset-theory

Get generic interface extension


Consider the following interfaces:

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

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

I looking for a generic solution to get the interface/type:

interface C extends B, A {
}

Where C would be like the interface D:

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

So I could have a function:

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

It doesn't have to be an interface. A type would do it also (I think).

The type A & B does not work because then I have an intersection (e.g. the value would be of type number & string).


Solution

  • I think I got it:

    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;
    

    Thank you @Oblosys for your help!