type TagValue = T extends Tag ? V : never export const match = >(pattern: { [key in T['tag'] | '_']?: (v: TagValue) => R }) => (tag: T): R => ((pattern as any)[tag.tag] || (pattern._ as any))(tag.value) type Tag = { tag: N; value: V } export type Enum = { [N in keyof T]: Tag }[keyof T] export const constructors = >(): { [N in T['tag']]: TagValue extends null | never ? (value?: null | never) => T : (value: TagValue) => T } => new Proxy( {}, { get(_, k) { return (value: any) => ({ tag: k, value }) }, }, ) as any