Last active
July 31, 2024 14:27
-
-
Save motss/76287e28079b4211de3af8e4565fd89d to your computer and use it in GitHub Desktop.
Simple implementation of Option, Some, None, and match() in TypeScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
type Some<T> = { some: T, none: false }; | |
type None = { some: undefined, none: true }; | |
type Option<T = unknown> = Some<T> | None; | |
type InferredSome<T extends Option> = T extends Some<infer R> ? | |
R : | |
never; | |
type OptionResult<T = unknown> = T extends null | undefined ? None : Some<T>; | |
function option<T>(value: T): OptionResult<T> { | |
if (value != null) { | |
return some(value) as OptionResult<T>; | |
} | |
return none() as OptionResult<T>; | |
} | |
function none(): None { | |
return { some: undefined, none: true }; | |
} | |
function some<T>(value: T): Some<T> { | |
return { some: value, none: false }; | |
} | |
class Matcher<T extends Option> { | |
#data!: T; | |
constructor(data: T) { | |
this.#data = data; | |
} | |
static new<U extends Option>(data: U) { | |
return new Matcher(data); | |
} | |
whenSome(cb: (value: InferredSome<T>) => void): Omit<Matcher<T>, 'whenSome'> { | |
cb(this.#data as InferredSome<T>); | |
return this; | |
} | |
whenNone(cb: () => void): Omit<Matcher<T>, 'whenNone'> { | |
cb(); | |
return this; | |
} | |
} | |
function match<T extends Option>(input: T) { | |
return new Matcher(input); | |
} | |
function fa() { | |
return Math.random() > .5 ? | |
some(Math.random()) : | |
none(); | |
} | |
const fav = fa(); | |
if (fav.none) { | |
console.debug('none?', fav.some); | |
} else { | |
console.debug('some?', fav.some); | |
} | |
match(fav) | |
.whenNone(() => console.debug('nil')) | |
.whenSome((value) => console.debug({ value })); | |
const a = option(undefined); | |
type A = typeof a extends Some<infer R> ? R : None; | |
// ^? |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment