Last active
September 16, 2024 20:11
-
-
Save bhalash/926a1a9f2ac72c43c3a2fed894994eef to your computer and use it in GitHub Desktop.
homebrew recreation of util.promisify
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
/** | |
* My original mistake was trying to pluck the argument and return types using | |
* the Parameters<Fn> and Arguments<Fn> generic helpers. It...got messy. | |
* | |
* The method overrides act like a switch statement for type. When given a | |
* function as an argument, Typescript looks through the overrides to see which | |
* one matches. | |
* | |
* Take this function, which takes a callback and prints out the given name | |
* through it: | |
* | |
* @example | |
* | |
* export type Callback<T = void> = (error: any, result: T) => void; | |
* | |
* export function printNameCallback(name: string, callback: Callback<string>): void { | |
* callback(null, name); | |
* } | |
* | |
* When I pass this to toPromise, it looks through the overrides until it finds | |
* the version that fits the function signature: | |
* | |
* @example | |
* | |
* export function toPromise<A1, TResult>( | |
* fn: (arg1: A1, callback: Callback<TResult>) => void | |
* ): (arg1: A1) => Promise<TResult>; | |
* | |
* // printNamePromise(arg1: string): Promise<string> | |
* const printNamePromise = toPromise(printNameCallback); | |
* | |
* From this, the Typescript compiler can infer the correct number and type of | |
* arguments for the promisified function. | |
*/ | |
export type Callback<T = unknown> = (error: any, result: T) => void; | |
export function printNameCallback(name: string, callback: Callback<string>): void { | |
callback(null, name); | |
} | |
export function printSum(a: number, b: number, callback: Callback<number>): void { | |
callback(null, a + b); | |
} | |
export function toPromise(fn: (callback: Callback) => void): () => Promise<void>; | |
export function toPromise<TResult>(fn: (callback: Callback<TResult>) => void): () => Promise<TResult>; | |
export function toPromise<A1, TResult>(fn: (arg1: A1, callback: Callback<TResult>) => void): (arg1: A1) => Promise<TResult>; | |
export function toPromise<A1, A2, TResult>(fn: (arg1: A1, arg2: A2, callback: Callback<TResult>) => void): (arg1: A1, arg2: A2) => Promise<TResult>; | |
export function toPromise<A1, A2, A3, TResult>(fn: (arg1: A1, arg2: A2, arg3: A3, callback: Callback<TResult>) => void): (arg1: A1, arg2: A2, arg3: A3) => Promise<TResult>; | |
export function toPromise<T>(fn: Function) { | |
if (typeof fn !== 'function') { | |
throw new TypeError('Passed argument is not a function.'); | |
} | |
return (...args: any[]): Promise<T> => { | |
return new Promise((resolve, reject) => { | |
return fn(...args, (error: any, result: any) => { | |
if (error) { | |
return reject(error); | |
} else { | |
return resolve(result); | |
} | |
}); | |
}); | |
}; | |
} | |
printNameCallback('Garrett', (_err, name) => console.log(name)); | |
toPromise(printNameCallback)('Garrett').then(console.log); | |
const printNamePromise = toPromise(printNameCallback); | |
printNamePromise('Blah'); | |
const promiseSum = toPromise(printSum); | |
promiseSum(3, 7).then(console.log); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment