56 lines
1.6 KiB
TypeScript
56 lines
1.6 KiB
TypeScript
export type None = {readonly _tag: 'None'}
|
|
export type Some<A> = {readonly _tag: 'Some', readonly value: A}
|
|
export type Option<A> = Some<A> | None
|
|
|
|
// Constructors
|
|
export const none: Option<never> = {_tag: 'None'}
|
|
export const some = <A>(value: A): Option<A> => ({
|
|
_tag: 'Some',
|
|
value,
|
|
})
|
|
|
|
// Operations
|
|
export const map = <A, B>(f: (a: A) => B) => (fa: Option<A>): Option<B> =>
|
|
fa._tag === 'Some' ? some(f(fa.value)) : none
|
|
|
|
export const chain =
|
|
<A, B>(f: (a: A) => Option<B>) => (fa: Option<A>): Option<B> =>
|
|
fa._tag === 'Some' ? f(fa.value) : none
|
|
|
|
export const getOrElse = <A>(defaultValue: A) => (fa: Option<A>): A =>
|
|
fa._tag === 'Some' ? fa.value : defaultValue
|
|
|
|
export class DoOption<T extends Record<string, unknown>> {
|
|
constructor(private readonly option: Option<T>) {}
|
|
|
|
bind<K extends string, A>(key: K, fa: Option<A>): DoOption<T & Record<K, A>> {
|
|
const newOption = chain((scope: T) =>
|
|
map((a: A) => ({...scope, [key]: a}))(fa)
|
|
)(this.option)
|
|
return new DoOption(newOption as Option<T & Record<K, A>>)
|
|
}
|
|
|
|
return<B>(f: (scope: T) => B): Option<B> {
|
|
return map(f)(this.option)
|
|
}
|
|
|
|
done(): Option<T> {
|
|
return this.option
|
|
}
|
|
do(fa: Option<unknown>): DoOption<T> {
|
|
const newOption = chain((scope: T) => map(() => scope)(fa))(this.option)
|
|
return new DoOption(newOption)
|
|
}
|
|
|
|
doL(f: (scope: T) => Option<unknown>): DoOption<T> {
|
|
const newOption = chain((scope: T) => map(() => scope)(f(scope)))(
|
|
this.option,
|
|
)
|
|
return new DoOption(newOption)
|
|
}
|
|
|
|
static start(): DoOption<{}> {
|
|
return new DoOption(some({}))
|
|
}
|
|
}
|