Skip to content

Commit 143d0d3

Browse files
committed
feat: make piscina entrypoint easier for typescript
1 parent c43b078 commit 143d0d3

File tree

6 files changed

+86
-7
lines changed

6 files changed

+86
-7
lines changed

docs/docs/getting-started/typescript.mdx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,3 +112,32 @@ const piscina = new Piscina({
112112
})();
113113
```
114114

115+
## Using generics
116+
117+
You can use generics to the types for the worker function:
118+
119+
```typescript title='worker.ts'
120+
121+
interface Inputs {
122+
a: number;
123+
b: number;
124+
}
125+
126+
export default function addNumbers({ a, b }: Inputs): number {
127+
return a + b;
128+
}
129+
```
130+
131+
```typescript title='main.ts'
132+
133+
import Piscina from 'piscina';
134+
135+
const piscina = new Piscina<typeof import("./worker.ts")>({
136+
filename: new URL("./worker.ts", import.meta.url).href,
137+
});
138+
139+
(async () => {
140+
const result = await piscina.run({ a: 2, b: 3 });
141+
console.log('Result:', result);
142+
})();
143+
```

package-lock.json

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"c8": "^10.1.2",
5252
"concat-stream": "^2.0.0",
5353
"eslint": "^9.16.0",
54+
"expect-type": "^1.2.1",
5455
"gen-esm-wrapper": "^1.1.1",
5556
"neostandard": "^0.12.0",
5657
"tap": "^16.3.7",

src/index.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,18 @@ interface FilledOptions extends Options {
9797
workerHistogram: boolean,
9898
}
9999

100-
interface RunOptions {
100+
interface RunOptions<Func = string> {
101101
transferList? : TransferList,
102102
filename? : string | null,
103103
signal? : AbortSignalAny | null,
104-
name? : string | null
104+
name? : Func | null
105105
}
106106

107-
interface FilledRunOptions extends RunOptions {
107+
interface FilledRunOptions<Func extends string = string> extends RunOptions<Func> {
108108
transferList : TransferList | never,
109109
filename : string | null,
110110
signal : AbortSignalAny | null,
111-
name : string | null
111+
name : Func | null
112112
}
113113

114114
interface CloseOptions {
@@ -481,7 +481,7 @@ class ThreadPool {
481481

482482
runTask (
483483
task : any,
484-
options : RunOptions) : Promise<any> {
484+
options : RunOptions<string>) : Promise<any> {
485485
let {
486486
filename,
487487
name
@@ -720,7 +720,7 @@ class ThreadPool {
720720
}
721721
}
722722

723-
export default class Piscina<T = any, R = any> extends EventEmitterAsyncResource {
723+
export default class Piscina<Exports extends Record<string, (payload: any) => any> = Record<string, (payload: any) => any>> extends EventEmitterAsyncResource {
724724
#pool : ThreadPool;
725725
#histogram: PiscinaHistogram | null = null;
726726

@@ -793,7 +793,7 @@ export default class Piscina<T = any, R = any> extends EventEmitterAsyncResource
793793
this.#pool = new ThreadPool(this, options);
794794
}
795795

796-
run (task : T, options : RunOptions = kDefaultRunOptions): Promise<R> {
796+
run <Func extends keyof Exports = 'default'>(task : Parameters<Exports[Func]>[0], options : RunOptions<Func> = kDefaultRunOptions as RunOptions<Func>): Promise<ReturnType<Exports[Func]>> {
797797
if (options === null || typeof options !== 'object') {
798798
return Promise.reject(
799799
new TypeError('options must be an object'));

test/fixtures/worker-type.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
export function greet({ name }: { name: string }): string {
2+
return `Hello ${name}!`;
3+
}
4+
5+
export default function add({ a, b }: { a: number; b: number }): number {
6+
return a + b;
7+
}

test/types-entrypoint.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { resolve } from "node:path";
2+
import { expectTypeOf } from "expect-type";
3+
4+
import { test } from "tap";
5+
6+
import Piscina from "../dist";
7+
8+
test("types can be inferred from function", async (t) => {
9+
const pool = new Piscina<typeof import("./fixtures/worker-type.js")>({
10+
filename: resolve(__dirname, "fixtures/worker-type.js"),
11+
concurrentTasksPerWorker: 1,
12+
});
13+
14+
expectTypeOf(pool.run).toExtend<(payload: { a: number; b: number }) => Promise<number>>();
15+
expectTypeOf(pool.run).toExtend<(payload: { a: number; b: number }, opts: { name: "default" }) => Promise<number>>();
16+
expectTypeOf(pool.run).toExtend<(payload: { name: string }, opts: { name: "greet" }) => Promise<string>>();
17+
});
18+
19+
test("types can be manually specified", async (t) => {
20+
const pool = new Piscina<{
21+
default: (payload: { a: number; b: number }) => number;
22+
greet: (payload: { name: string }) => string;
23+
}>({
24+
filename: resolve(__dirname, "fixtures/worker-type.js"),
25+
concurrentTasksPerWorker: 1,
26+
});
27+
28+
expectTypeOf(pool.run).toExtend<(payload: { a: number; b: number }) => Promise<number>>();
29+
expectTypeOf(pool.run).toExtend<(payload: { a: number; b: number }, opts: { name: "default" }) => Promise<number>>();
30+
expectTypeOf(pool.run).toExtend<(payload: { name: string }, opts: { name: "greet" }) => Promise<string>>();
31+
});

0 commit comments

Comments
 (0)