SnabelS
Denoβ€’3y ago
Snabel

My magic middlewares type

If anyone wants a typescript challange here is one: I am trying to create a tuple type which contains an sequence of MiddlewareHandler types. This MiddlewareHandler is defined as:
export type MiddlewareHandler<I = unknown, O extends I = I> = (
  req: Request,
  ctx: MiddlewareContext<I, O>,
) => Response | Promise<Response>;

I have a function called compose which composes these MiddlewareHandlers. This function takes a generic array of MiddlewareHandler:
type ExtractInput<T extends readonly MiddlewareHandler[]> = T[0] extends
  MiddlewareHandler<infer I> ? I : never;
type ExtractOutput<T extends readonly MiddlewareHandler[]> =
  T[T["length"]] extends MiddlewareHandler<infer _, infer O> ? O : never;

export function compose<T extends readonly MiddlewareHandler[]>(
  middlewares: T,
  handler: Handler<ExtractOutput<T>>,
): Handler<ExtractInput<T>> { ... }

this however does not work, as it complains when using it like following:
export const auth = {
  "/logout": compose(
    [session(), authenticated()] as const,
    logout
  ),
  "/github": github
} satisfies Routes;

Argument of type 'readonly [MiddlewareHandler<unknown, SessionState>, MiddlewareHandler<SessionState, Required<SessionState>>]' is not assignable to parameter of type 'readonly MiddlewareHandler<unknown, unknown>[]'.
  Type 'MiddlewareHandler<unknown, SessionState> | MiddlewareHandler<SessionState, Required<SessionState>>' is not assignable to type 'MiddlewareHandler<unknown, unknown>'.
    Type 'MiddlewareHandler<SessionState, Required<SessionState>>' is not assignable to type 'MiddlewareHandler<unknown, unknown>'.
      Types of parameters 'ctx' and 'ctx' are incompatible.
        Type 'MiddlewareContext<unknown, unknown>' is not assignable to type 'MiddlewareContext<SessionState, Required<SessionState>>'.
          Property 'session' is missing in type 'MiddlewareContext<unknown, unknown>' but required in type 'Required<SessionState>'.deno-ts(2345)


Plus points:
I would ideally also like the T generic type to require that all following MiddlewareHandlers have the its generic I set to the previous O like following type:
[MiddlewareHandler<unknown, A>, MiddlewareHandler<A, B>, MiddlewareHandler<B, C>];
                            ^>------------------->^  ^>------------------->^
Was this page helpful?