Created
April 4, 2017 09:30
-
-
Save datokrat/d0545e9240d0f3010be8fe298265bbb4 to your computer and use it in GitHub Desktop.
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 function just<T>(value: T): Just<T> { | |
return new _Just<T>(value) as Just<T>; | |
} | |
export function nothing(): Nothing<any> { | |
return new _Nothing() as Nothing<any>; | |
} | |
export interface MBase<T> { | |
type: "just" | "nothing"; | |
map<U>(this: Just<T>, project: (t: T) => U): Just<U>; | |
map<U>(this: Nothing<T>, project: (t: T) => U): Nothing<U>; | |
map<U>(project: (t: T) => U): Maybe<U>; | |
or(this: Just<T>, alternative: Maybe<T>): Just<T>; | |
or<U>(this: Nothing<T>, alternative: Just<U>): Just<U>; | |
or<U>(this: Nothing<T>, alternative: Nothing<U>): Nothing<U>; | |
or(this: Maybe<T>, alternative: Just<T>): Just<T>; | |
or<U>(this: Nothing<T>, alternative: Maybe<U>): Maybe<U>; | |
or(alternative: Maybe<T>): Maybe<T>; | |
flatten<U>(this: Maybe<Maybe<U>>): Maybe<U>; | |
}; | |
export interface Just<T> extends MBase<T> { | |
type: "just"; | |
readonly value: T; | |
}; | |
export interface Nothing<T> extends MBase<T> { | |
type: "nothing"; | |
} | |
export type Maybe<T> = Just<T> | Nothing<T>; | |
export function isJust<T>(x: Maybe<T>): x is Just<T> { | |
return x.type === "just"; | |
} | |
export function isNothing<T>(x: Maybe<T>): x is Nothing<T> { | |
return x.type === "nothing"; | |
} | |
abstract class _Maybe<T> implements MBase<T> { | |
public type: "nothing" | "just"; | |
public map<U>(this: Just<T>, project: (t: T) => U): Just<U>; | |
public map<U>(this: Nothing<T>, project: (t: T) => U): Nothing<U>; | |
public map<U>(this: Maybe<T>, project: (t: T) => U): Maybe<U> { | |
const m: Maybe<T> = this; | |
return isJust(m) ? just(project(m.value)) : nothing(); | |
} | |
public or(this: Just<T>, alternative: Maybe<T>): Just<T>; | |
public or(this: Nothing<T>, alternative: Just<T>): Just<T>; | |
public or(this: Nothing<T>, alternative: Nothing<T>): Nothing<T>; | |
public or(this: Nothing<T>, alternative: Maybe<T>): Maybe<T>; | |
public or(this: Maybe<T>, alternative: Just<T>): Just<T>; | |
public or(this: Maybe<T>, alternative: Maybe<T>): Maybe<T> { | |
return isJust(this) ? this : alternative; | |
} | |
public flatten<U>(this: Maybe<Maybe<U>>): Maybe<U> { | |
const m: Maybe<Maybe<U>> = this; | |
return isJust(m) ? m.value : nothing(); | |
} | |
} | |
class _Nothing extends _Maybe<never> { | |
public readonly type = "nothing"; | |
} | |
class _Just<T> extends _Maybe<T> { | |
public readonly type = "just"; | |
constructor(public readonly value: T) { super() } | |
} |
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
import {} from "./maybe"; | |
const one = just("Hello World").value; // OK | |
const bad = nothing().value; // Compile error | |
const two = just("Hello World").or(nothing()).value; // OK | |
const three = nothing().or(just("Hello World")).value; // OK | |
const baaad = nothing().or(nothing()).value; // Compile error | |
const four = just("Hello World").map(x => `${x}!`).value; // OK | |
const five = nothing().map(x => `${x}!`).value; // Compile error | |
const six = just(just("Hello World")).flatten(); // OK; typeof six == Maybe<string> | |
const seven = just("Hello World").flatten(); // Compile error | |
function logMaybe(m: Maybe<string>) { | |
// Type guards work | |
if (isJust(m)) console.log(m.value); // OK | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment