-
Notifications
You must be signed in to change notification settings - Fork 86
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
Typescript types? #3
Comments
I'm not against that, but it would make statically analyzing the exports mostly impossible. export default async function worker() {
await sleep() // yay, optional async init
// define methods here as you mentioned
return { method, method2 }
}
// then in the consumer:
import worker from 'workerize!./worker'
worker().then( async inst => {
await inst.method()
}) One really neat advantage here is that it would allow for the module exports to instead be collected at runtime and sent to the parent thread via the existing RPC |
I just dropped this library into my typescript project and it was really easy to use, but it's tough loosing the type safety. are there any plans/issues/prs where I could see (and maybe help) the effort towards this feature? |
My style like this: // ./workers/md5.worker.ts
import md5 from './lib/md5'
export function md5(file: File) {
return md5(file)
} // then in the consumer:
import * as md5Worker from './workers/md5.worker'
const { md5 } = (md5Worker as any)() as typeof md5Worker
// md5 type in vscode is: (file: File) => Promise<{}> |
Well this loader was ridiculously easy to set up 🥇 @developit 🙏 I think it's even easier in TypeScript—if you use // worker.ts
export async function expensive(time: number) {
const start = Date.now();
let count: number = 0;
while (Date.now() - start < time) {
count++;
}
return count;
} // app.ts
import ExampleWorker from './workers/example.worker';
const instance = ExampleWorker();
instance.expensive(1000).then(count => {
console.log(`Ran ${count} loops`);
}); Type checking works well: |
Agreed - best practise I'd recommend for everyone using |
Could anyone here provide a small demo repository? At the moment I'm struggling a little bit with this and don't get it to work.
|
My webpack config is default and simple: {
test: /\.worker\.js$/,
use: [
{ loader: 'workerize-loader' },
]
} When you function md5Worker() {
return {
md5(file) {}
}
} But typescript thinking the type is type md5Worker = {
md5: (file: File) => Promise<{}>
} So we need fool typescript. const { md5 } = (md5Worker as any /* I'm not object, i'm a function */)() as typeof md5Worker /* The result of function is md5Worker */
Because there is no way to tell typescript what types in the |
Thank you for your feedback, but this doesn't work. I created a small demo repo. Just make a By the way: is this on purpose that you wrote |
oops! I'm sorry. I forget my ts files compiled by vscode task. I think you need update your module: {
rules: [
{
test: /\.worker\.ts$/,
use: ["workerize-loader", "ts-loader"]
},
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/
}
]
} And your export async function md5(): Promise<string> {
return "12345";
} In md5().then((hash: string) => alert(hash)); |
There should be a easy way to expose the |
I actually found a way to wrap the import to get the I created a wrapper function: // create-worker.ts
type WorkerType<T> = T & Pick<Worker, 'terminate'>;
export function createWorker<T>(workerPath: T): WorkerType<T> {
return (workerPath as any)();
}
export type createWorker<T> = WorkerType<T>; Then import it into the module where you want the web worker: // app.ts
import { createWorker } from './create-worker'
import * as ExampleWorker from './example-worker';
const instance = createWorker(ExampleWorker);
instance.expensive(1000);
instance.terminate(); I have an example here: https://stackblitz.com/edit/typescript-zlgfwe |
I ended up with this, which is not perfect, but seems like a good alternative to casting to // global.d.ts
declare module "workerize-loader!*" {
type AnyFunction = (...args: any[]) => any;
type Async<F extends AnyFunction> = (...args: Parameters<F>) => Promise<ReturnType<F>>;
type Workerized<T> = Worker & { [K in keyof T]: T[K] extends AnyFunction ? Async<T[K]> : never };
function createInstance<T>(): Workerized<T>;
export = createInstance;
} // foo.worker.ts
export function foo(a: number, b: number) {
// here is where you expensive work happens
return a + b;
}
export function bar(a: number, b: number) {
// here is where you expensive work happens
return a * b;
} // main.ts
import createFooWorker from "workerize-loader!./foo.worker";
import * as FooWorker from "./foo.worker";
const fooWorker = createFooWorker<typeof FooWorker>();
async function main() {
const result = await fooWorker.foo(1, 2);
const result2 = await fooWorker.bar(2, 3);
fooWorker.terminate(); // works as well
} There are probably ways to optimize this further, but this works without too much hassle for my use-case. |
@phil-lgr You don't have |
@Menci i think workerize would create the default for you, and the module u will be importing is really imported to a workerize module as its functions but not directly imported into your other module. |
@developit if it's any help, here's how I dealt with the type safety issue in my own build process that doesn't use workerize https://www.obvibase.com/dev-blog/how-obvibase-uses-web-workers and it has worked out really well. I wonder if the same approach (.ui and .worker file naming convention) would work for you as well, even if you don't use TS compiler... |
Its a bit difficult to write a definition file... any ideas how to handle that?
Would be easier if the export was the factory function that returns the exported functions:
then the types would be identical if the functions return promises.
The text was updated successfully, but these errors were encountered: