Created
December 9, 2023 14:23
-
-
Save flysand7/5742f3a756a002e4bb8b21fac9c22fbe to your computer and use it in GitHub Desktop.
functional-typescript-test
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
import * as http from "http"; | |
type Result<T, E> = readonly [T, null] | readonly [null, E]; | |
function Ok<E, T>(value: T): readonly [T, null] { | |
return [value, null] as const; | |
} | |
function Err<E, T>(error: E): readonly [null, E] { | |
return [null, error] as const; | |
} | |
function isOk<E,T>([res, err]: Result<T,E>): boolean { | |
return res != null; | |
} | |
function MatchOk<T,E>([res, err]: Result<T,E>): [T, boolean] { | |
return [res as T, res !== null]; | |
} | |
function MatchErr<T,E>([res, err]: Result<T,E>): [E, boolean] { | |
return [err as E, err !== null]; | |
} | |
function isErr<E,T>([res, err]: Result<T,E>): boolean { | |
return err != null; | |
} | |
type Maybe<T> = T | null; | |
function Some<T>(value: T): Maybe<T> { | |
return value; | |
} | |
function None<T>(): Maybe<T> { | |
return null; | |
} | |
function MatchSome<T>(value: Maybe<T>): [T, boolean] { | |
return [value as T, value !== null]; | |
} | |
function MatchNone<T>(value: Maybe<T>): [null, boolean] { | |
return [null, value === null]; | |
} | |
function promise_maybe<T>(promise: Promise<T>): Promise<Maybe<T>> { | |
return promise | |
.then((r) => Some(r)) | |
.catch((e) => None()); | |
} | |
function promise_result<T>(promise: Promise<T>): Promise<Result<T, Error>> { | |
return promise | |
.then((r) => Ok(r)) | |
.catch((e) => Err(e)); | |
} | |
function http_get(url: string): Promise<Result<Buffer, Error>> { | |
return promise_result(new Promise((resolve, reject) => { | |
http.get(url, (result) => { | |
let data: Buffer[] = []; | |
result.on('data', chunk => { | |
data.push(chunk); | |
}); | |
result.on('end', () => { | |
resolve(Buffer.concat(data)); | |
}); | |
}).on('error', (e) => { | |
reject(e); | |
}); | |
})); | |
} | |
class Fatal extends Error {} | |
type MatchFunc<T,M> = (value: T)=>[M, boolean]; | |
type ResultFunc<M,R> = (value: M)=>R; | |
class MatchingState<T, ExclSet=T, ResSet=never> { | |
private matched = false; | |
private computed!: ResSet; | |
constructor(private value: T) {} | |
with<M,R>(match: MatchFunc<T,M>, result: ResultFunc<M,R>): MatchingState<T, Exclude<ExclSet, M>, ResSet|R> { | |
if(this.matched) { | |
return this as unknown as MatchingState<T, Exclude<ExclSet, M>, ResSet | R>; | |
} | |
const [res, ok] = match(this.value) | |
if(ok) { | |
this.computed = result(res) as unknown as ResSet; | |
this.matched = true; | |
} | |
return this as unknown as MatchingState<T, Exclude<ExclSet, M>, ResSet | R>; | |
} | |
otherwise<R>(result: ResultFunc<ExclSet, R>): ResSet|R { | |
return result(this.value as unknown as ExclSet) | |
} | |
complete(): (never extends ExclSet ? ResSet : never) { | |
return this.computed as (never extends ExclSet ? ResSet : never); | |
} | |
} | |
function match<T>(value: T): MatchingState<T> { | |
return new MatchingState(value); | |
} | |
function fatal(message: string): never { | |
throw new Fatal(message) | |
} | |
async function test_requests(): Promise<void> { | |
console.log("Trying to connect to an address"); | |
const response_2 = match(await http_get('http://google.com')) | |
.with(MatchOk, res => String(res)) | |
.with(MatchErr, err => fatal(`Unable to connect`)) | |
.complete(); | |
console.log(response_2); | |
} | |
test_requests(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment