Skip to content

Instantly share code, notes, and snippets.

@dezfowler
Last active August 6, 2019 12:39
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dezfowler/cc5012581093080f54763ffe8e54988b to your computer and use it in GitHub Desktop.
Save dezfowler/cc5012581093080f54763ffe8e54988b to your computer and use it in GitHub Desktop.
Typed visitor discriminated union
function calculateArea(shape: Shape): number {
switch(shape.__typename) {
case 'Circle':
return Math.PI * (shape.radius ^ 2);
case 'Rectangle':
return shape.width * shape.height;
case 'Square':
return shape.side ^ 2;
case 'Triangle':
return (shape.base / 2) * shape.height;
default:
const nope: never = shape;
return nope;
}
}
function calculateArea(shape: Shape): number {
switch(shape.__typename) {
case 'Circle':
return Math.PI * (shape.radius ^ 2);
case 'Rectangle':
return shape.width * shape.height;
case 'Square':
return shape.side ^ 2;
case 'Triangle':
return (shape.base / 2) * shape.height;
}
}
const shape: Shape = {
__typename: 'Circle',
radius: 5
};
const area = calculateArea(shape);
/**
* TUnion The union type
* TDiscriminator The discriminator property name
*/
type UnionKeys<TUnion, TDisciminator extends keyof TUnion> =
TUnion[TDisciminator] extends string | number | symbol ?
TUnion[TDisciminator] : never;
/**
* TUnion The union type
* TDiscriminator The discriminator property name
* TDiscriminatorValue The discriminator value to retrieve the union part
*/
type UnionPartForKey<
TUnion,
TDisciminator extends keyof TUnion,
TDiscriminatorValue extends UnionKeys<TUnion, TDisciminator>
> =
TUnion extends any ?
TDiscriminatorValue extends TUnion[TDisciminator] ?
TUnion
: never
: never;
/**
* TUnion The union type
* TDiscriminator The discriminator property name
* TReturn Return type for the strategy functions
*/
type UnionMap<
TUnion,
TDisciminator extends keyof TUnion,
TReturn = void
> = {
[K in UnionKeys<TUnion, TDisciminator>]: (part: UnionPartForKey<TUnion, TDisciminator, K>) => TReturn
};
type Circle = {
__typename: "Circle";
radius: number;
};
type Rectangle = {
__typename: "Rectangle";
width: number;
height: number;
};
type Square = {
__typename: "Square";
side: number;
};
type Triangle = {
__typename: "Triangle";
base: number;
height: number;
};
type Shape = Circle | Square | Rectangle | Triangle;
const areaCalculation: UnionMap<Shape, '__typename', number> = {
Circle: shape => Math.PI * (shape.radius ^ 2),
Rectangle: shape => shape.width * shape.height,
Square: shape => shape.side ^ 2,
Triangle: shape => (shape.base / 2) * shape.height
};
const shape: Shape = {
__typename: 'Circle',
radius: 5
};
const area = areaCalculation[shape.__typename](shape);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment