Skip to content

Instantly share code, notes, and snippets.

@gund
Last active November 25, 2019 16:51
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save gund/13c0c6c01e49cbef4946fd73de78ee25 to your computer and use it in GitHub Desktop.
Save gund/13c0c6c01e49cbef4946fd73de78ee25 to your computer and use it in GitHub Desktop.
Helper type to merge conflicting interfaces
/**
* Simple merge of two types where first `T1` will override second `T2`
*/
export type MergeSimple<T1, T2> = T1 & Omit<T2, keyof T1>;
/**
* Recursive merge of array of types where first types take over the last ones
*/
export type Merge<T extends any[]> = MergeRecursive<Head<T>, Tail<T>>;
type Head<T extends any[]> = T extends [infer X, ...any[]] ? X : never;
type Tail<T extends any[]> = ((...x: T) => void) extends (
x: any,
...xs: infer XS
) => void
? XS
: never;
type MergeRecursive<
T1,
TRest extends any[],
FirstAndSecond = MergeSimple<T1, Head<TRest>>
> = {
0: FirstAndSecond;
1: FirstAndSecond & MergeRecursive<FirstAndSecond, Tail<TRest>>;
}[TRest extends [] ? 0 : TRest extends [any] ? 0 : 1];
import { Merge, MergeSimple } from './merge-types';
interface A {
readonly lol: string;
prop1: string;
}
interface B {
lol: boolean;
prop2?: boolean;
}
interface B2 {
lol: string[];
prop2: string;
prop3: number;
}
type CSimple = MergeSimple<A, B>;
let cSimple: CSimple;
cSimple.lol; // readonly (property) A.lol: string
cSimple.prop1; // (property) A.prop1: string
cSimple.prop2; // (property) prop2?: boolean
type C = Merge<[A, B, B2]>;
let c: C;
c.lol; // readonly (property) A.lol: string
c.prop1; // (property) A.prop1: string
c.prop2; // (property) prop2?: boolean
c.prop3; // (property) prop3: number
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment