Last active
November 15, 2018 01:36
-
-
Save baetheus/13b6bfa7c3759f721afdbc8ba0053c94 to your computer and use it in GitHub Desktop.
Complement Type
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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