export type ADTMember = Extract< ADT, { [k in Key]: Type } > type Matchers = { [D in ADT[Key]]: (v: ADTMember) => Out } export const matchOn = (key: K) => < ADT extends { [k in K]: string }, Z >( matchObj: Matchers, ) => (v: ADT) => matchObj[v[key]](v as ADTMember) export const matchOnI = (key: K) => < ADT extends { [k in K]: string } >( v: ADT, ) => (matchObj: Matchers) => matchObj[v[key]](v as ADTMember) /** * Pattern matcher for matching over tagged unions whose discriminant value is "tag" * @example * ```ts * export type TicketDetail = | { tag: 'tracking' } | { tag: 'info' contents: TicketInfoRequest } | { tag: 'change' contents: TicketChangeRequest } declare const detail: TicketDetail pipe(detail, match({ tracking: () => "I'm super tracked!", info: i => i.contents.status, change: c => c.contents.justification })) * ``` */ export const match = matchOn('tag') /** * Like {@link match} but inverted argument order * @example * ```ts * export type TicketDetail = | { tag: 'tracking' } | { tag: 'info' contents: TicketInfoRequest } | { tag: 'change' contents: TicketChangeRequest } declare const detail: TicketDetail matchI(detail)({ tracking: () => "I'm super tracked!", info: i => i.contents.status, change: c => c.contents.justification }) * ``` */ export const matchI = matchOnI('tag') export const matchS = (s: S) => ( matchObj: { [M in S]: () => Out }, ): Out => matchObj[s]()