Typescript callbacks not passing types down when nested

I’m using Nextjs for a project and I’ve created the following interface to decorate other functions:

import type { NextApiRequest, NextApiResponse, NextApiHandler } from 'next';

interface ApiHandlerDecorator<T, S> {
  <Request extends NextApiRequest, Response extends NextApiResponse>(
    handler: (
      request: Request & T,
      response: Response | NextApiResponse<S>
    ) => ReturnType<NextApiHandler>
  ): (
    request: Request & T,
    response: Response | NextApiResponse<S>
  ) => ReturnType<NextApiHandler>;
}

export default ApiHandlerDecorator;

I have two decorators:

import { verify } from 'jsonwebtoken';

import type { ApiHandlerDecorator } from './interfaces';

import {
  BadRequestError,
  ExpiredCredentialsError,
  InvalidCredentialsError,
  MissingCredentialsError,
  UnexpectedError,
} from './pages/api/errors';

type AuthorizationValidationErrors =
  | MissingCredentialsError
  | InvalidCredentialsError
  | ExpiredCredentialsError
  | UnexpectedError
  | BadRequestError
  | undefined;

const authorizationValidation: ApiHandlerDecorator<
  { headers: { authorization: string } },
  AuthorizationValidationErrors
> = (handler) => async (request, response) => {
  const {
    headers: { authorization },
  } = request;

  let statusCode = 401;
  let json: AuthorizationValidationErrors = new MissingCredentialsError(
    'Missing authorization header'
  );

  if (authorization) {
    try {
      const decodedJwt = verify(authorization, process.env.SECRET_KEY);

      if (
        decodedJwt &&
        typeof decodedJwt === 'object' &&
        'roomId' in decodedJwt &&
        'playerId' in decodedJwt
      ) {
        await handler(
          { ...request, ...{ headers: { authorization } } },
          response
        );
      } else {
        statusCode = 400;
        json = new BadRequestError(
          'Malformed authorization. Missing roomId and playerId.'
        );
      }
    } catch ({ name: errorName }) {
      if (errorName === 'JsonWebTokenError') {
        statusCode = 401;
        json = new InvalidCredentialsError(
          'Invalid authorization. Authorization not signed.'
        );
      } else if (errorName === 'TokenExpiredError') {
        statusCode = 403;
        json = new ExpiredCredentialsError(
          'Expired authorization. Refresh authorization.'
        );
      } else {
        statusCode = 500;
        json = new UnexpectedError(
          'Unexpected error while processing authorization'
        );
      }
    }
  } else {
    response.status(statusCode).json(json);
  }
};

export default authorizationValidation;

and

import type { ApiHandlerDecorator } from './interfaces';

import { decode } from 'jsonwebtoken';
import { BadRequestError, MissingCredentialsError } from './pages/api/errors';

type RoomAndPlayerIdInjectionErrors =
  | BadRequestError
  | MissingCredentialsError
  | undefined;

const roomAndPlayerIdInjection: ApiHandlerDecorator<
  { roomId: string; playerId: string },
  RoomAndPlayerIdInjectionErrors
> = (handler) => async (request, response) => {
  const {
    headers: { authorization },
  } = request;

  if (authorization) {
    const decodedJwt = decode(authorization);

    if (
      decodedJwt &&
      typeof decodedJwt === 'object' &&
      'roomId' in decodedJwt &&
      'playerId' in decodedJwt
    ) {
      await handler(
        {
          ...request,
          roomId: decodedJwt.roomId,
          playerId: decodedJwt.playerId,
        },
        response
      );
    } else {
      response
        .status(400)
        .json(
          new BadRequestError(
            'Malformed authorization. Missing roomId and playerId.'
          )
        );
    }
  } else {
    response
      .status(401)
      .json(
        new MissingCredentialsError(
          'Missing authorization. Authorization header not provided.'
        )
      );
  }
};

export default roomAndPlayerIdInjection;

When I decorate a function like this:

const handler = authorizationValidation(
  roomAndPlayerIdInjection(async (request, response) => {
    // request.headers.authorization is string | undefined
  });
);

If I change call order and do:

const handler = roomAndPlayerIdInjection(
  authorizationValidation(async (request, response) => {
    // request.roomId and request.playerId is undefined
  });
);

But, when I do:

type Handler = typeof handler;

The Handler request parameter is perfectly typed.

Playground with working example

Is this a problem with Typescript or Next.js? Am I doing something wrong? Should I be using experimental decorators instead?