Skip to content

feat: make piscina entrypoint easier for typescript #801

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: current
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions docs/docs/getting-started/typescript.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,32 @@ const piscina = new Piscina({
})();
```

## Using generics

You can use generics to the types for the worker function:

```typescript title='worker.ts'

interface Inputs {
a: number;
b: number;
}

export default function addNumbers({ a, b }: Inputs): number {
return a + b;
}
```

```typescript title='main.ts'

import Piscina from 'piscina';

const piscina = new Piscina<typeof import("./worker.ts")>({
filename: new URL("./worker.ts", import.meta.url).href,
});

(async () => {
const result = await piscina.run({ a: 2, b: 3 });
console.log('Result:', result);
})();
```
11 changes: 11 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
"c8": "^10.1.2",
"concat-stream": "^2.0.0",
"eslint": "^9.16.0",
"expect-type": "^1.2.1",
"gen-esm-wrapper": "^1.1.1",
"neostandard": "^0.12.0",
"tap": "^16.3.7",
Expand Down
14 changes: 7 additions & 7 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,18 @@ interface FilledOptions extends Options {
workerHistogram: boolean,
}

interface RunOptions {
interface RunOptions<Func = string> {
transferList? : TransferList,
filename? : string | null,
signal? : AbortSignalAny | null,
name? : string | null
name? : Func | null
}

interface FilledRunOptions extends RunOptions {
interface FilledRunOptions<Func extends string = string> extends RunOptions<Func> {
transferList : TransferList | never,
filename : string | null,
signal : AbortSignalAny | null,
name : string | null
name : Func | null
}

interface CloseOptions {
Expand Down Expand Up @@ -481,7 +481,7 @@ class ThreadPool {

runTask (
task : any,
options : RunOptions) : Promise<any> {
options : RunOptions<string>) : Promise<any> {
let {
filename,
name
Expand Down Expand Up @@ -720,7 +720,7 @@ class ThreadPool {
}
}

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

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

run (task : T, options : RunOptions = kDefaultRunOptions): Promise<R> {
run <Func extends keyof Exports = 'default'>(task : Parameters<Exports[Func]>[0], options : RunOptions<Func> = kDefaultRunOptions as RunOptions<Func>): Promise<ReturnType<Exports[Func]>> {
if (options === null || typeof options !== 'object') {
return Promise.reject(
new TypeError('options must be an object'));
Expand Down
7 changes: 7 additions & 0 deletions test/fixtures/worker-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export function greet({ name }: { name: string }): string {
return `Hello ${name}!`;
}

export default function add({ a, b }: { a: number; b: number }): number {
return a + b;
}
31 changes: 31 additions & 0 deletions test/types-entrypoint.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { resolve } from "node:path";
import { expectTypeOf } from "expect-type";

import { test } from "tap";

import Piscina from "../dist";

test("types can be inferred from function", async (t) => {
const pool = new Piscina<typeof import("./fixtures/worker-type.js")>({
filename: resolve(__dirname, "fixtures/worker-type.js"),
concurrentTasksPerWorker: 1,
});

expectTypeOf(pool.run).toExtend<(payload: { a: number; b: number }) => Promise<number>>();
expectTypeOf(pool.run).toExtend<(payload: { a: number; b: number }, opts: { name: "default" }) => Promise<number>>();
expectTypeOf(pool.run).toExtend<(payload: { name: string }, opts: { name: "greet" }) => Promise<string>>();
});

test("types can be manually specified", async (t) => {
const pool = new Piscina<{
default: (payload: { a: number; b: number }) => number;
greet: (payload: { name: string }) => string;
}>({
filename: resolve(__dirname, "fixtures/worker-type.js"),
concurrentTasksPerWorker: 1,
});

expectTypeOf(pool.run).toExtend<(payload: { a: number; b: number }) => Promise<number>>();
expectTypeOf(pool.run).toExtend<(payload: { a: number; b: number }, opts: { name: "default" }) => Promise<number>>();
expectTypeOf(pool.run).toExtend<(payload: { name: string }, opts: { name: "greet" }) => Promise<string>>();
});
Loading