Skip to content

Instantly share code, notes, and snippets.

@Schniz
Created July 21, 2021 14:51
Show Gist options
  • Save Schniz/3dc86e354a43da8ec67e8e42833afa4b to your computer and use it in GitHub Desktop.
Save Schniz/3dc86e354a43da8ec67e8e42833afa4b to your computer and use it in GitHub Desktop.
type Thenable<T> = {
then<R, L = never>(onFulfill: (t: T) => R, onError?: (err: any) => L): Thenable<R | L>,
catch<L>(onError: (err: any) => L): Thenable<T | L>,
}
type Result<T> = { type: "value", value: T } | { type: "error", error: any };
/** Wrapper around simple functions that allow you to `.catch` and `.then` for synchronous functions */
function thenable<T>(createT: () => T): Thenable<T> {
let resultT: Result<T>;
try {
resultT = { type: "value", value: createT() };
} catch (e) {
resultT = { type: "error", error: e }
}
return {
then(resolve, reject) {
if (resultT.type === "value") {
const t = resultT.value;
return thenable(() => resolve(t));
} else if (reject) {
const err = resultT.error;
return thenable(() => reject(err));
} else {
const err = resultT.error;
return thenable(() => { throw err });
}
},
catch(reject) {
if (resultT.type === "error") {
const err = resultT.error;
return thenable(() => reject(err))
}
const t = resultT.value;
return thenable(() => t);
}
}
}
/**
* Takes a function and returns a function that can be `.then` and `.catch`ed
*/
function chained<F extends (...args: any[]) => any>(f: F): (this: ThisParameterType<F>, ...args: Parameters<F>) => Thenable<ReturnType<F>> {
return function (...args) {
return thenable(() => f(...args));
}
}
// ---
function throws(v: string) {
if (Math.random() > 0.5) {
throw new Error("Alright.")
}
return v
}
async function thrower() {
const f = chained(throws);
try {
const v = await f("Hello, world!");
console.log(v);
} catch (e) {
console.log(`Oh no: ${e}`);
}
}
thrower();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment