type TagValue = T extends Tag ? V : never export const match = >( tag: T, pattern: { [key in T['tag'] | '_']?: (v: TagValue) => R }, ): R => ((pattern as any)[tag.tag] || (pattern._ as any))(tag.value) // type TagValues< // T extends Tag, // Keys extends Array, // Values extends Array = [], // > = Keys extends [] // ? Values // : Keys extends [ // infer key extends string, // ...infer restOfKeys extends string[], // ] // ? TagValues]> // : never // // export const ifLet = , Keys extends Array>( // tag: T, // kinds: Keys, // cb: (...values: TagValues) => void, // ): void => { // const values = kinds.map(k => (tag.tag === k ? tag.value : undefined)) // ;(cb as any)(...values) // } export const matchString = ( key: T, pattern: { [key in T | '_']?: (key: key) => R }, ): R => ((pattern as any)[key] || (pattern._ as any))(key) 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