Unfortunately, as of 0.9.5, TypeScript doesn\'t (yet) have algebraic data types (union types) and pattern matching (to destructure them). What\'s more, it doesn\'t even supp
This is an old question, but maybe this will still help someone:
Like @SorenDebois's answer, this one has half of the per-case boilerplate as @theSoft's. It is also more encapsulated than @Soren's. Additionally, this solution has type safety, switch-like behavior, and forces you to check all cases.
// If you want to be able to not check all cases, you can wrap this type in `Partial<...>`
type MapToFuncs = { [K in keyof T]: (v: T[K]) => void }
// This is used to extract the enum value type associated with an enum.
type ValueOfEnum<_T extends Enum, U = any> = EnumValue
class EnumValue {
constructor(
private readonly type: keyof T,
private readonly value?: T[keyof T]
) {}
switch(then: MapToFuncs) {
const f = then[this.type] as (v: T[keyof T]) => void
f(this.value)
}
}
// tslint:disable-next-line: max-classes-per-file
class Enum {
case(k: K, v: T[K]) {
return new EnumValue(k, v)
}
}
Usage:
// Define the enum. We only need to mention the cases once!
const GameState = new Enum<{
NotStarted: {}
InProgress: { round: number }
Ended: {}
}>()
// Some function that checks the game state:
const doSomethingWithState = (state: ValueOfEnum) => {
state.switch({
Ended: () => { /* One thing */ },
InProgress: ({ round }) => { /* Two thing with round */ },
NotStarted: () => { /* Three thing */ },
})
}
// Calling the function
doSomethingWithState(GameState.case("Ended", {}))
The one aspect here that is really not ideal is the need for ValueOfEnum. In my application, that was enough for me to go with @theSoft's answer. If anyone knows how to compress this, drop a comment below!