Created
September 25, 2021 23:12
-
-
Save OliverBrotchie/319ae829eb901f33072ee9e3cc933153 to your computer and use it in GitHub Desktop.
Types for Optionals
This file contains 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
const None = Symbol("None"); | |
const DefaultErr = Symbol("Err"); | |
type Option<T> = ((s: (val: T) => T) => T) | typeof None; | |
type Some<T> = (val: T) => Option<T>; | |
const Some: <T>(val: T) => Option<T> = (val) => (s) => s(val); | |
type Result<T, E> = (o: (val: T) => E, s: (val: symbol) => E) => E; | |
type Err<T> = T; | |
const Err: <A, B>(val: symbol) => Result<A, B> = (val: symbol) => (_, g) => | |
g(val); | |
const Ok: <T, E>(val: T) => Result<T, E> = (val) => (f, _) => f(val); | |
function unwrap<T, U>(value: Option<T> | Result<T, U>): T { | |
if ((value as Option<T>) === None) throw `unwrap called on None`; | |
else if (typeof value == "function") { | |
return (value as Result<T, T>)( | |
(val) => val as T, | |
(val) => { | |
throw `unwrap called on ${val.toString()}`; | |
} | |
); | |
} else return value as unknown as T; | |
} | |
// Usage of both result and option in a function | |
function divide( | |
numerator: unknown, | |
denominator: unknown | |
): Result<Option<number>, Err<typeof DefaultErr>> { | |
if (typeof numerator != "number" || typeof denominator != "number") { | |
return Err(DefaultErr); | |
} else if (denominator == 0) { | |
return Ok(None); | |
} else { | |
return Ok(Some(numerator / denominator)); | |
} | |
} | |
console.log(unwrap(unwrap(divide(4, 2)))); |
This file contains 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
export class Option<T> { | |
private constructor(private isSome: boolean, private value?: T) {} | |
unwrap(): T { | |
if (!this.isSome) { | |
throw new Error("Option is none"); | |
} | |
return this.value as T; | |
} | |
static Some<T>(value: T) { | |
return new Option(true, value); | |
} | |
static None: Option<never> = new Option(false); | |
} | |
function divide(numerator: number, denominator: number): Option<number> { | |
if (denominator == 0) { | |
return Option.None; | |
} else { | |
return Option.Some(numerator / denominator); | |
} | |
} | |
console.log(divide(4, 2).unwrap()); |
This file contains 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
function createSome<T>(value: T) { | |
return new SomeClass(value); | |
} | |
export interface OptionalGeneric<T> { | |
isSome: boolean; | |
unwrap(): T; | |
map<U>(transform: (value: T) => U): Option<U>; | |
or<U>(value: U): T | U; | |
} | |
export class SomeClass<T> implements OptionalGeneric<T> { | |
readonly value: T; | |
readonly isSome = true; | |
constructor(value: T) { | |
this.value = value; | |
} | |
unwrap(): T { | |
return this.value; | |
} | |
map<U>(transform: (value: T) => U) { | |
return new SomeClass(transform(this.value)); | |
} | |
or<U>(_: U) { | |
return this.value; | |
} | |
} | |
class NoneClass implements OptionalGeneric<never> { | |
readonly isSome = false; | |
unwrap(): never { | |
throw new Error("called unwrap on None"); | |
} | |
map() { | |
return this; | |
} | |
or<U>(value: U) { | |
return value; | |
} | |
} | |
export type Some<T> = SomeClass<T>; | |
export const Some = createSome; | |
const instance = new NoneClass(); | |
export type None = typeof instance; | |
export const None = instance; | |
export type Option<T> = Some<T> | None; | |
function divide(numerator: number, denominator: number): Option<number> { | |
if (denominator == 0) { | |
return None; | |
} else { | |
return Some(numerator / denominator); | |
} | |
} | |
console.log(divide(4, 2).unwrap()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment