Skip to content

Commit 9f4bda2

Browse files
committed
feat: promisify utility now preserves typing info
1 parent 3bbca0d commit 9f4bda2

3 files changed

Lines changed: 32 additions & 7 deletions

File tree

src/bin/polykey-agent.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const logger = new Logger('polykey', undefined, [new StreamHandler()]);
3737
*/
3838
async function main(_argv = process.argv): Promise<number> {
3939
const exitHandlers = new binUtils.ExitHandlers();
40-
const processSend = promisify<void>(process.send!.bind(process));
40+
const processSend = promisify(process.send!.bind(process));
4141
const { p: messageInP, resolveP: resolveMessageInP } =
4242
promise<AgentChildProcessInput>();
4343
process.once('message', (data: AgentChildProcessInput) => {

src/types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ type POJO = { [key: string]: any };
1313
type Opaque<K, T> = T & { readonly [brand]: K };
1414
declare const brand: unique symbol;
1515

16+
/**
17+
* Generic callback
18+
*/
19+
type Callback<P extends Array<any> = [], R = any, E extends Error = Error> = {
20+
(e: E, ...params: Partial<P>): R;
21+
(e?: null | undefined, ...params: P): R;
22+
};
23+
1624
/**
1725
* Non-empty array
1826
*/
@@ -81,6 +89,7 @@ type FileHandle = fs.promises.FileHandle;
8189
export type {
8290
POJO,
8391
Opaque,
92+
Callback,
8493
NonEmptyArray,
8594
AbstractConstructorParameters,
8695
Initial,

src/utils/utils.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { FileSystem, Timer } from '../types';
1+
import type { FileSystem, Timer, Callback } from '../types';
22
import os from 'os';
33
import process from 'process';
44
import path from 'path';
@@ -138,18 +138,34 @@ async function poll<T, E = any>(
138138

139139
/**
140140
* Convert callback-style to promise-style
141+
* If this is applied to overloaded function
142+
* it will only choose one of the function signatures to use
141143
*/
142-
function promisify<T>(f): (...args: any[]) => Promise<T> {
143-
return function <T>(...args): Promise<T> {
144+
function promisify<
145+
T extends Array<unknown>,
146+
P extends Array<unknown>,
147+
R extends T extends [] ? void : T extends [unknown] ? T[0] : T,
148+
>(
149+
f: (...args: [...params: P, callback: Callback<T>]) => unknown,
150+
): (...params: P) => Promise<R> {
151+
// Uses a regular function so that `this` can be bound
152+
return function (...params: P): Promise<R> {
144153
return new Promise((resolve, reject) => {
145154
const callback = (error, ...values) => {
146155
if (error != null) {
147156
return reject(error);
148157
}
149-
return resolve(values.length === 1 ? values[0] : values);
158+
if (values.length === 0) {
159+
(resolve as () => void)();
160+
} else if (values.length === 1) {
161+
resolve(values[0] as R);
162+
} else {
163+
resolve(values as R);
164+
}
165+
return;
150166
};
151-
args.push(callback);
152-
f.apply(this, args);
167+
params.push(callback);
168+
f.apply(this, params);
153169
});
154170
};
155171
}

0 commit comments

Comments
 (0)