diff --git a/index.d.ts b/index.d.ts new file mode 100644 index 0000000..60d14b1 --- /dev/null +++ b/index.d.ts @@ -0,0 +1,30 @@ +type Last = T extends [...any, infer L] + ? L + : never; +type DropLast = T extends [...(infer U), any] + ? U + : []; + +interface Options { + multiArgs: boolean; +} + +type Promisify = ( + ...args: DropLast +) => Last extends (...args: any) => any + ? Promise< + TOptions extends { multiArgs: false } + ? Last>> + : Parameters> + > + : never; + +declare function pify< + TArgs extends readonly unknown[], + TOptions extends Options = { multiArgs: false } +>( + input: (...args: TArgs) => any, + options?: TOptions +): Promisify; + +export = pify; diff --git a/index.test-d.ts b/index.test-d.ts new file mode 100644 index 0000000..d053ab3 --- /dev/null +++ b/index.test-d.ts @@ -0,0 +1,96 @@ +import { expectError, expectType } from "tsd"; +import pify = require("."); + +expectError(pify()); +expectError(pify(null)); +expectError(pify(undefined)); +expectError(pify(123)); +expectError(pify("abc")); +expectError(pify(null, {})); +expectError(pify(undefined, {})); +expectError(pify(123, {})); +expectError(pify("abc", {})); + +expectType(pify((v: number) => {})()); + +// callback with 0 additional params +declare function fn0(fn: (val: number) => void): void; +expectType>(pify(fn0)()); + +// callback with 1 additional params +declare function fn1(x: number, fn: (val: number) => void): void; +expectType>(pify(fn1)(1)); + +// callback with 2 additional params +declare function fn2(x: number, y: number, fn: (val: number) => void): void; +expectType>(pify(fn2)(1, 2)); + +// generics + +declare function generic(val: T, fn: (val: T) => void): void; +declare const genericVal: "hello" | "goodbye"; +expectType>(pify(generic)(genericVal)); + +declare function generic10( + val1: T1, + val2: T2, + val3: T3, + val4: T4, + val5: T5, + val6: T6, + val7: T7, + val8: T8, + val9: T9, + val10: T10, + cb: (value: { + val1: T1; + val2: T2; + val3: T3; + val4: T4; + val5: T5; + val6: T6; + val7: T7; + val8: T8; + val9: T9; + val10: T10; + }) => void +): void; +expectType< + Promise<{ + val1: 1; + val2: 2; + val3: 3; + val4: 4; + val5: 5; + val6: 6; + val7: 7; + val8: "8"; + val9: 9; + val10: 10; + }> +>(pify(generic10)(1, 2, 3, 4, 5, 6, 7, "8", 9, 10)); + +// multiArgs +declare function callback02(cb: (x: number, y: string) => void): void; +declare function callback12(val: "a", cb: (x: number, y: string) => void): void; +declare function callback22( + val1: "a", + val2: "b", + cb: (x: number, y: string) => void +): void; + +expectType>(pify(callback02, { multiArgs: true })()); +expectType>( + pify(callback12, { multiArgs: true })("a") +); +expectType>( + pify(callback22, { multiArgs: true })("a", "b") +); + +// overloads +declare function overloaded(value: number, cb: (value: number) => void): void; +declare function overloaded(value: string, cb: (value: string) => void): void; + +// Chooses last overload +// See https://github.com/microsoft/TypeScript/issues/32164 +expectType>(pify(overloaded)("")); diff --git a/package.json b/package.json index a5e5075..13f2d3b 100644 --- a/package.json +++ b/package.json @@ -16,11 +16,12 @@ "node": ">=14.16" }, "scripts": { - "test": "xo && ava", + "test": "xo && ava && tsd", "optimization-test": "node --allow-natives-syntax optimization-test.js" }, "files": [ - "index.js" + "index.js", + "index.d.ts" ], "keywords": [ "promisify", @@ -45,6 +46,8 @@ "devDependencies": { "ava": "^4.3.0", "pinkie-promise": "^2.0.1", + "tsd": "^0.19.0", + "typescript": "^4.5.4", "v8-natives": "^1.2.5", "xo": "^0.49.0" } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..aee0ec9 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,5 @@ +{ + "compilerOptions": { + "strict": true + } +}