Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Request types resolving to unknown when setting route prehandlers #138

Open
2 tasks done
zacharynoble opened this issue Apr 15, 2024 · 3 comments
Open
2 tasks done

Comments

@zacharynoble
Copy link

zacharynoble commented Apr 15, 2024

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.26.2

Plugin version

4.0.0

Node.js version

21.4.0

Operating system

macOS

Operating system version (i.e. 20.04, 11.3, 10)

13.1

Description

Without passing preHandlers to to a route, I get automatic typesafety on request objects based on the defined schema.

When I do pass preHandlers which are using the request or reply objects, the types disappear, resolving to unknown and causing TS errors.

Steps to Reproduce

This code works:

const fastify = Fastify().withTypeProvider<TypeBoxTypeProvider>()

fastify.post('/', {
  schema: {
    body: Type.Object({
      x: Type.String(),
      y: Type.Number(),
      z: Type.Boolean()
    })
  }
}, (req) => {
  const { x, y, z } = req.body // x,y,z are typed properly
})

However, If I try to pass a preHandler, i.e. to verify authentication, all of the request values lose their typing and become 'unknown', yielding TS type errors when I try to reference those variables.

This code causes TypeScript errors:

export const authenticateUser = (req: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => {
    ....
};

...

const fastify = Fastify().withTypeProvider<TypeBoxTypeProvider>()

fastify.post('/', {
  schema: {
    body: Type.Object({
      x: Type.String(),
      y: Type.Number(),
      z: Type.Boolean()
    })
   },
   preHandler: authenticateUser // this is what causes the problems
  }
}, (req) => {
  const { x, y, z } = req.body // ERROR: Property 'x' does not exist on type 'unknown', ...same for y and z
})

The strangest thing is that I can fix this error and get back type safety by passing an explicit callback to the preHandler as such:

preHandler: (req, reply, done) => authenticateUser(req, reply, done)

or

preHandler: (...args) => authenticateUser(...args)

Another way to fix this is to set the types for the req / reply params in the plugin to any. Which is certainly wrong, albeit potentially illuminating.

This same exact error occurs with the Zod type provider as well. There is an open issue on this, a couple months old, with many comments but no resolution.

Thank you for any help you can direct at this, I'm sure it will help the many people who I have seen stuck on this issue!

@zacharynoble zacharynoble changed the title Request/Response types resolving to unknown when setting route prehandlers Request types resolving to unknown when setting route prehandlers Apr 15, 2024
@kburdett
Copy link

I have encountered this issue as well. I don't think that this is an issue with the TypeBox provider though. I found the best solution for me was to allow for generic inputs into the authenticate function itself.

export function authenticateUser<T extends FastifyRequest, U extends FastifyReply>(req: T, reply: U, done: HookHandlerDoneFunction) {
    ...
}

Oddly, I had to also modify the preHandler to be in array format. This one left me a bit baffled. I wasn't able to trace the relevant types through Fastify's massive generics chaining to explain it. I gave up and just put it in an array.

preHandler: [authenticateUser],

@zacharynoble
Copy link
Author

zacharynoble commented Apr 17, 2024

I actually tried that exact same thing, but I didn't try it as an array so I wrote it off as not an option. Good find, I think that's a bit better than the solution I found. Just gonna do that for now.

@m4rvr
Copy link

m4rvr commented Apr 22, 2024

Yeah, this has been an issue for a long time. It also works if you just put an as any after like

preHandler: authenticateUser as any

Then you don't even need the generics in the function. But the array + generics is a great catch too, using it now 😆

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants