Last active
June 1, 2020 00:34
-
-
Save pufface/6a2050b21a692d2400c35bbe3536552c to your computer and use it in GitHub Desktop.
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
class Square { | |
type = "Square" as const | |
constructor(public side: number) {} | |
} | |
class Circle { | |
type = "Circle" as const | |
constructor(public radius: number) {} | |
} | |
class Rectangle { | |
type = "Rectangle" as const | |
constructor(public width: number, public height: number) {} | |
} | |
type Shape = Square | Circle | Rectangle | |
type ShapeType = Shape["type"] | |
type ShapeMap<U> = { [K in ShapeType]: U extends { type: K } ? U : never } | |
type ShapeTypeMap = ShapeMap<Shape> | |
type Pattern<T> = { [K in keyof ShapeTypeMap]: (shape: ShapeTypeMap[K]) => T } | |
function matcher<T>(pattern: Pattern<T>): (shape: Shape) => T { | |
// https://github.com/Microsoft/TypeScript/issues/14107 | |
return shape => pattern[shape.type](shape as any) | |
} | |
const shapes = [new Circle(4.0), new Square(5.0), new Rectangle(6.0, 7.0)] | |
const area = matcher<number>({ | |
Square: square => square.side * square.side, | |
Circle: circle => circle.radius * circle.radius * Math.PI, | |
Rectangle: rect => rect.height * rect.width | |
}) | |
const totalArea = shapes.reduce((acc, shape) => acc + area(shape), 0) | |
console.log(`Total area: ${totalArea}`) | |
const perimeter = matcher<number>({ | |
Square: square => 4 * square.side, | |
Circle: circle => 2 * Math.PI * circle.radius, | |
Rectangle: rect => 2 * rect.height + 2 * rect.width | |
}) | |
const sumPerimeter = shapes.reduce((acc, shape) => acc + perimeter(shape), 0) | |
console.log(`Total perimeter: ${sumPerimeter}`) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment