worker-tools / middleware

Placeholder for Worker-based middleware solution

Home Page:https://workers.tools/middleware

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

No typings for `ctx` and `env`?

davej opened this issue · comments

This is an awesome lib and I'm getting a ton of value from it. I find myself having to jump through hoops to get things typed properly though. Perhaps I am doing things wrong?

Here is an example of how I'm trying to create a new typedParams middleware to add a downloadParams object. And also adding typings for ctx and env (because otherwise they are any type). Is there a better way to do this?

interface DownloadParams {
  appId?: string;
  appVersion?: string;
}

interface Env {
  R2_BUCKET: R2Bucket;
  ORIGIN_URL: string;
  ENVIRONMENT: "dev" | "prod";
}


type AddCtxAndEnvType<T> = Omit<T, "ctx" | "env"> & {
  ctx?: ExecutionContext;
  env?: Env;
};

type Awaitable<T> = T | PromiseLike<T>;
type TypedMiddleware<T extends (...args) => any> = Handler<
  Awaited<ReturnType<T>> & RouteContext
>;
const typedParams =
  () =>
  async <X extends BasicsContext>(
    ax: Awaitable<X>
  ): Promise<X & { downloadParams?: DownloadParams }> => {
    const x = await ax;
    return Object.assign(x, { downloadParams: x.params as DownloadParams });
  };

const middleware = combine(basics(), typedParams());

const handler: TypedMiddlware<typeof middleware> = async (
  req,
  {
    downloadParams,
    userAgent,
    env,
    ctx,
    waitUntil,
    url,
  }: AddCtxAndEnvType<Parameters<TypedMiddleware<typeof middleware>>[1]>
): Promise<Response> => {
  // ...
}

Hey, I'm glad you're getting value out of it.

There's a createMiddleware function, but I've just realized it is too limited for your case. You could take it as a starting point to make your own middleware factory fn though.. EDIT: Link to function

Both the things you're trying to do should arguably be part of the library itself, but I'm not having any good ideas on how to do this right now.

Thanks @qwtel. Can I build upon an existing middleware like the basics middleware? For example, if I wanted to type the route's params using the DownloadParams type. Could I do something like this?

createMiddleware({ downloadParams: {} }, async <BasicsContext>(ax) => {
  const x = await ax;
  return {
    ...x,
    downloadParams: x.params as DownloadParams,
  };
});

When I do the above then ax isn't typed:
CleanShot 2022-10-19 at 4 19 30@2x

For example, if I wanted to type the route's params using the DownloadParams type. Could I do something like this?

Yeah, you could create your own copy. The source is pretty short.