1
Fork 0

typescript(option): feat: added the base helpers

Signed-off-by: prescientmoon <git@moonythm.dev>
This commit is contained in:
Matei Adriel 2019-12-19 13:26:22 +02:00 committed by prescientmoon
parent 052584b09a
commit b388fb76aa
Signed by: prescientmoon
SSH key fingerprint: SHA256:UUF9JT2s8Xfyv76b8ZuVL7XrmimH4o49p4b+iexbVH4
5 changed files with 142 additions and 0 deletions

View file

@ -0,0 +1,110 @@
import { Option, Some, None } from './types'
import { Binder, Folder, Mapper, Predicate, BackFolder } from './internalTypes'
import Internals, { SomeClass } from './internals'
export const isSome = <T>(option: Option<T>) =>
option instanceof Internals.SomeClass
export const isNothing = <T>(option: Option<T>) =>
option instanceof Internals.NoneClass
export const match = <T, U>(
option: Option<T>,
caseSome: (v: T) => U,
caseNone: () => U
) => {
if (isSome(option)) {
return caseSome((option as SomeClass<T>)[Internals.someValue])
}
return caseNone()
}
export const bind = <T, U>(
binder: Binder<T, U>,
option: Option<T>
): Option<U> => {
return match(option, binder, () => None)
}
export const map = <T, U>(
mapper: Mapper<T, U>,
option: Option<T>
): Option<U> => {
return match(
option,
v => Some(mapper(v)),
() => None
)
}
export const count = <T>(option: Option<T>) => Number(isSome(option))
export const exists = <T>(predicate: Predicate<T>, option: Option<T>) => {
return match(option, predicate, () => false)
}
export const filter = <T>(predicate: Predicate<T>, option: Option<T>) => {
return match(
option,
v => (predicate(v) ? Some(v) : None),
() => None
)
}
export const fold = <T, U>(
folder: Folder<T, U>,
initial: U,
option: Option<T>
) => {
match(
option,
v => folder(initial, v),
() => initial
)
}
export const foldback = <T, U>(
folder: BackFolder<T, U>,
option: Option<T>,
initial: U
) => {
return match(
option,
v => folder(v, initial),
() => initial
)
}
export const forall = <T>(predicate: Predicate<T>, option: Option<T>) => {
return match(option, predicate, () => true)
}
export const get = <T>(option: Option<T>) => {
return match(
option,
v => v,
() => {
throw new Error('Cannot get value from None')
}
)
}
export const iter = <T>(mapper: Mapper<T, void>, option: Option<T>) => {
match(option, mapper, () => {})
}
export const toArray = <T>(option: Option<T>) => {
return match(
option,
v => [v],
() => []
)
}
export const toNullable = <T>(option: Option<T>) => {
return match(
option,
v => v,
() => null
)
}

View file

@ -0,0 +1,2 @@
export * from './helpers'
export * from './types'

View file

@ -0,0 +1,7 @@
import { Option } from './types'
export type Mapper<T, U> = (v: T) => U
export type Binder<T, U> = Mapper<T, Option<U>>
export type Predicate<T> = Mapper<T, boolean>
export type Folder<T, U> = (s: U, v: T) => U
export type BackFolder<T, U> = (v: T, s: U) => U

View file

@ -0,0 +1,17 @@
export const isOption = Symbol('option')
export const someValue = Symbol('value')
export class SomeClass<T> {
public [isOption] = true
public [someValue]: T
public constructor(value: T) {
this[someValue] = value
}
}
export class NoneClass {
public [isOption] = true
}
export default { NoneClass, SomeClass, isOption, someValue }

View file

@ -0,0 +1,6 @@
import * as Internals from './internals'
export type Option<T> = Internals.SomeClass<T> | Internals.NoneClass
export const None = new Internals.NoneClass()
export const Some = <T>(v: T) => new Internals.SomeClass(v)