Last active
August 6, 2019 12:39
-
-
Save dezfowler/cc5012581093080f54763ffe8e54988b to your computer and use it in GitHub Desktop.
Typed visitor discriminated union
This file contains 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
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; | |
} | |
} |
This file contains 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
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); |
This file contains 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
/** | |
* 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 | |
}; |
This file contains 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 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; |
This file contains 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
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