Skip to content

Instantly share code, notes, and snippets.

@YBogomolov
Created May 15, 2019 12:17
Show Gist options
  • Save YBogomolov/25ec2aa4bb8c25abce1fcc7b887ede66 to your computer and use it in GitHub Desktop.
Save YBogomolov/25ec2aa4bb8c25abce1fcc7b887ede66 to your computer and use it in GitHub Desktop.
Type-level laws: "function arguments should never intersect"
export type If<T, U, True, False> = [T] extends [U] ? True : False;
export type IfDef<T, Yep, Nope> = If<T, never, Nope, Yep>;
export type Intersect<A extends {}, B extends {}> =
Pick<A, Exclude<keyof A, Exclude<keyof A, keyof B>>> extends { [x: string]: never } ?
never :
Pick<A, Exclude<keyof A, Exclude<keyof A, keyof B>>>;
const f = <
A extends {},
B extends {},
// Typelevel law: A and B should not intersect
NeverIntersect = IfDef<Intersect<A, B>, never, {}>
>(a: A & NeverIntersect, b: B & NeverIntersect): A & B & NeverIntersect => ({ ...a, ...b });
interface IA {
foo: string;
}
interface IB {
bar: number;
}
const a1: IA = { foo: 'foo' };
const b1: IB = { bar: 42 };
const c1 = f<IA, IB>(a1, b1); // c1 :: IA & IB
const c2 = f<IA, IA>(a1, a1); // Argument of type 'IA' is not assignable to parameter of type 'never'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment