Skip to content

Broken typings when upgrading to 21.4.0 #4547

Open

Description

@svrnwnsch

Runtime

node.js

Runtime version

22.15.1

Module version

21.4.0

Last module version without issue

21.3.12

Used with

No response

Any other relevant information

No response

What are you trying to achieve or the steps to reproduce?

We have handle who look simplified like this:

export const create = ():RouteOptions => ({
  handler: async (req: Request<{ Payload: { from: string; to: string; } }>, h: ResponseToolkit): Promise<ResponseObject> => {
    const from = req.payload.from
    const to = req.payload.to
    .....
    await someFunction(req);

    return h.response().code(201);
  },
});

export const someFunction = async (request: Request): Promise<void> => ({
   .....
})

What was the result you got?

I get a typescript error:

error TS2345: Argument of type 'Request<{ Payload: { from: string; to: string; }; }>' is not assignable to parameter of type 'Request<ReqRefDefaults>'.
  The types of 'route.settings.pre' are incompatible between these types.
    Type 'RouteOptionsPreArray<{ Payload: { from: string; to: string; }; }> | undefined' is not assignable to type 'RouteOptionsPreArray<ReqRefDefaults> | undefined'.
      Type 'RouteOptionsPreArray<{ Payload: { from: string; to: string; }; }>' is not assignable to type 'RouteOptionsPreAllOptions<ReqRefDefaults>[]'.
        Type 'RouteOptionsPreAllOptions<{ Payload: { from: string; to: string; }; }>' is not assignable to type 'RouteOptionsPreAllOptions<ReqRefDefaults>'.
          Type 'Method<{ Payload: { from: string; to: string; }; }, ReturnValue<{ Payload: { from: string; to: string; }; }>>' is not assignable to type 'RouteOptionsPreAllOptions<ReqRefDefaults>'.
            Type 'Method<{ Payload: { from: string; to: string; }; }, ReturnValue<{ Payload: { from: string; to: string; }; }>>' is not assignable to type 'Method<ReqRefDefaults, ReturnValue<ReqRefDefaults>>'.
              Types of parameters 'request' and 'request' are incompatible.
                Type 'Request<ReqRefDefaults>' is not assignable to type 'Request<{ Payload: { from: string; to: string; }; }>'.
                  Types of property 'payload' are incompatible.
                    Type 'string | object | Readable | Buffer<ArrayBufferLike>' is not assignable to type '{ from: string; to: string; }'.
                      Type 'string' is not assignable to type '{ from: string; to: string; }'.

To fix this problem I need to change:

export const someFunction = async (request: Request<{ Payload: { from: string; to: string; } }>): Promise<void> => ({
   .....
})

but this does not work out if someFunction is used by different handler with different payloads.

What result did you expect?

keep it the way as in 21.3.12 an not have an error here.

Activity

  1. damusix commented on May 21, 2025

    @damusix
    Contributor

    @svrnwnsch you might want to try using generics instead. someFunc = <R extends Request<any>> (req: R) => {...} so typescript matches any request type instead of a specific request type.

  2. svrnwnsch commented on Jul 22, 2025

    @svrnwnsch
    Author

    This works. I would still prefer that it worked as before and I do not need to use any as this is discouraged by our linter.

  3. damusix commented on Aug 4, 2025

    @damusix
    Contributor

    @svrnwnsch Yeah I completely understand. We try to also avoid any as much as possible, too. Do you have suggestions on how we might improve our typings?

    In short, what happens is the following:

    By stating async (request: Request) => any, you're telling TS: This Request matches the global Request<ReqRefDefaults> interface, instead of your strongly-typed Request<{ payload: { ... } }> . TS can't match your specific payload to (stream.Readable | Buffer | string | object)[https://github.com/hapijs/hapi/blob/master/lib/types/request.d.ts#L270] since it doesn't extend any of those data types.

    By stating someFunc = <R extends Request<any>> (req: R) => {...}, you're telling TS: infer R from Request (any ReqRefs).

    We're not using Request<any> as a basis because we want to enforce strong types, so you have to state <any> in your generic type. If you're creating a utility that's a route config factory, this is appropriate. Perhaps try stating unknown instead it would be more contractually correct? Try that and see if the linter still screams at you.

    It's also hard to tell how it was before for you, given that these typings have been this way for a while, and recent upgrades should not have affected anything except the Auth and HTTP method sections: https://github.com/hapijs/hapi/commits/master/lib/types/request.d.ts

  4. damusix commented on Feb 24, 2026

    @damusix
    Contributor

    @svrnwnsch Can you try with the 21.4.5 release? LMK how it behaves given your use case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugBug or defect

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions