Skip to content

Instantly share code, notes, and snippets.

@izakfilmalter
Created December 2, 2024 11:55
Show Gist options
  • Select an option

  • Save izakfilmalter/6745ef53a0fd865e7dc2c423e66cb71d to your computer and use it in GitHub Desktop.

Select an option

Save izakfilmalter/6745ef53a0fd865e7dc2c423e66cb71d to your computer and use it in GitHub Desktop.
Match
export type ADTMember<ADT, Key extends string, Type extends string> = Extract<
ADT,
/* eslint-disable @typescript-eslint/consistent-indexed-object-style */
{ [k in Key]: Type }
>
type Matchers<Key extends string, ADT extends { [k in Key]: string }, Out> = {
[D in ADT[Key]]: (v: ADTMember<ADT, Key, D>) => Out
}
export const matchOn =
<K extends string>(key: K) =>
<ADT extends { [k in K]: string }, Z>(matchObj: Matchers<K, ADT, Z>) =>
(v: ADT) =>
matchObj[v[key]](v as ADTMember<ADT, K, (typeof v)[K]>)
export const matchOnI =
<K extends string>(key: K) =>
<ADT extends { [k in K]: string }>(v: ADT) =>
<Z>(matchObj: Matchers<K, ADT, Z>) =>
matchObj[v[key]](v as ADTMember<ADT, K, (typeof v)[K]>)
/**
* 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')
export const matchType = matchOn('type')
/**
* 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 extends string>(s: S) =>
<Out>(matchObj: { [M in S]: () => Out }): Out =>
matchObj[s]()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment