Skip to content

Instantly share code, notes, and snippets.

@tylerbrostrom
Last active May 27, 2021 00:07
Show Gist options
  • Save tylerbrostrom/0672a9b1bbe932604cbc31158d6040c1 to your computer and use it in GitHub Desktop.
Save tylerbrostrom/0672a9b1bbe932604cbc31158d6040c1 to your computer and use it in GitHub Desktop.
TypeScript Utility for Creating Discriminating Unions
/**
Create a discriminating union type from two or more object types.
Why?:
- Saves you a few keystrokes.
- Esp. helpful for distinguishing between type aliases you don’t own.
Caveats:
- Discriminator property might clobber an existing property.
Type Params:
- `TMembers` - Union of tuples where `TMembers[0]` is the object type and `TMembers[1]` is the string value for the discriminator property.
- `TDiscriminator` (optional) - Name of the discriminator property. Defaults to `'kind'`.
@example
```
import type {Square, Circle} from 'some-library';
// type Circle = {
// radius: number;
// }
// type Square = {
// length: number
// }
type Shape = DiscriminatingUnion<[Circle, 'circle'] | [Square, 'square']>;
// type Shape =
// | {
// kind: 'circle';
// radius: number;
// }
// | {
// kind: 'square';
// length: number;
// }
// Profit!
function area(shape: Shape): number {
if (shape.kind === 'circle') {
return Math.PI * shape.radius ** 2;
} else if (shape.kind === 'square') {
return shape.length ** 2;
}
}
```
*/
type DiscriminatingUnion<TMembers, TDiscriminator extends string = 'kind'> = TMembers extends [
member: Record<string, any>,
kind: string
]
? TMembers[0] & { [K in TDiscriminator]: TMembers[1] }
: never;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment