Skip to content

Instantly share code, notes, and snippets.

@baetheus
Last active November 15, 2018 01:36
Show Gist options
  • Select an option

  • Save baetheus/13b6bfa7c3759f721afdbc8ba0053c94 to your computer and use it in GitHub Desktop.

Select an option

Save baetheus/13b6bfa7c3759f721afdbc8ba0053c94 to your computer and use it in GitHub Desktop.
Complement Type
type Complement<A, B> = {
[Key in keyof A]: Key extends keyof B ? never : A[Key]
};
// Simple Cascade
const cascade = <A>(a: A) => <B>(b: Complement<B, A>): A & B =>
Object.assign({}, a, b);
const c1 = cascade({ key1: 1 });
const c2 = c1({ key1: 2 }); // Type error, key1 must be never
const c3 = c1({ key2: 2 }); // Has type { key1: number, key2: number }
// More useful rolling box
interface RollingBox<V> {
value: V;
next: <N>(u: Complement<N, V>) => RollingBox<N & V>;
}
const rollingBox = <V>(value: V): RollingBox<V> => ({
value,
next: <N>(next: Complement<N, V>) =>
rollingBox(Object.assign({}, value, next) as V & N)
});
const r1 = rollingBox({ key1: 1 });
const r2 = r1.next({ key1: 2 }); // Type error
const r3 = r1.next({ key2: 2 });
const r4 = r3.value; // // Has type { key1: number, key2: number }
// Rolling box without the interface
const roll = <V>(value: V) => ({
value,
roll: <N>(next: Complement<N, V>) => roll(Object.assign({}, value, next )),
});
const a1 = roll({ key1: 1 });
const a2 = a1.roll({ key1: 2 }); // Type Error
const a3 = a1.roll({ key2: 2 });
const a4 = a3.value.key1 === 1 // true
const a5 = a3.roll({ key1: 2, key2: 3 }) // Type Error x 2
const a6 = a3.roll({ key3: 3 }); // { key1: number, key2: number, key3: number }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment