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,
};
});
For example, if I wanted to type the route's
params
using theDownloadParams
type. Could I do something like this?
Yeah, you could create your own copy. The source is pretty short.