fastify-type-provider-typebox
fastify-type-provider-typebox copied to clipboard
Request types resolving to unknown when setting route prehandlers
Prerequisites
- [X] I have written a descriptive issue title
- [X] 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!
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],
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.
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 😆