since const DEFAULT = '_' ; interface None { readonly _tag : 'None' ; } interface Some < A > { readonly _tag : 'Some' ; readonly value : A ; } since export type Option < A > = None | Some < A > ; interface DefaultCase { readonly _tag : typeof DEFAULT ; readonly value : unknown ; } interface DefaultCase { readonly [ DEFAULT ] : ( ) => unknown ; } type _Tag < T extends { readonly _tag : string ; } > = T [ '_tag' ] ; type MatchingType < T , Type extends string > = Extract < T , { readonly _tag : Type ; } > ; type X = 'left' | 'right' | 'value' ; type Match = { readonly [ k in X ] ? : unknown ; } & { readonly _tag : string ; } ; type MatchW < A , _Tag extends string , X , R > = ( p : Extract < A , { [ _tag in _Tag ] : X ; } > ) => R ; example since export function match < T extends Match | DefaultCase , R = unknown > ( pattern ) { return ( x ) => ( pattern as any ) [ x ?. _tag ?? DEFAULT ] ( x ) ; } example since export const matchW = ( _tag ) => ( k ) => ( match ) => { return k ?. [ match ?. [ _tag ] ] ? k [ match [ _tag ] ] ( match ) : k [ DEFAULT ] ( match ) ; } ;