fastify-auth
fastify-auth copied to clipboard
Typescript bug when used in conjunction with "fastify-type-provider-zod".
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.25.2
Plugin version
4.4.0
Node.js version
20.9.0
Operating system
macOS
Operating system version (i.e. 20.04, 11.3, 10)
14.2.1
Description
I came across a weird bug today when I was building my API. Basically when using @fastify/auth
plugin along with fastify-type-provider-zod
package typescript complains. I get the following error:
Type 'preHandlerHookHandler<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, RouteGenericInterface, unknown, FastifySchema, FastifyTypeProviderDefault, FastifyBaseLogger>' is not assignable to type 'onRequestHookHandler<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, RouteGenericInterface, unknown, FastifySchema, ZodTypeProvider, FastifyBaseLogger> | onRequestHookHandler<...>[] | undefined'.
Type 'preHandlerHookHandler<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, RouteGenericInterface, unknown, FastifySchema, FastifyTypeProviderDefault, FastifyBaseLogger>' is not assignable to type 'onRequestHookHandler<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, RouteGenericInterface, unknown, FastifySchema, ZodTypeProvider, FastifyBaseLogger>'.
The 'this' types of each signature are incompatible.
Type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, ZodTypeProvider>' is not assignable to type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>'.
The types returned by 'after()' are incompatible between these types.
Type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, ZodTypeProvider> & PromiseLike<...>' is not assignable to type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault> & PromiseLike<...>'.
Type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, ZodTypeProvider> & PromiseLike<...>' is not assignable to type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>'.
The types of 'addSchema(...).addHook' are incompatible between these types.
Type '{ <RouteGeneric extends import("/Users/geovla/Developer/Projects/apps/taskmaster/api/node_modules/.pnpm/[email protected]/node_modules/fastify/types/route").RouteGenericInterface = import("/Users/geovla/Developer/Projects/apps/taskmaster/api/node_modules/.pnpm/[email protected]/node_modules/fastify/types/route").RouteGene...' is not assignable to type '{ <RouteGeneric extends import("/Users/geovla/Developer/Projects/apps/taskmaster/api/node_modules/.pnpm/[email protected]/node_modules/fastify/types/route").RouteGenericInterface = import("/Users/geovla/Developer/Projects/apps/taskmaster/api/node_modules/.pnpm/[email protected]/node_modules/fastify/types/route").RouteGene...'. Two different types with this name exist, but they are unrelated.
Types of parameters 'hook' and 'hook' are incompatible.
Types of parameters 'opts' and 'opts' are incompatible.
Type 'RouteOptions<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, any, any, any, ZodTypeProvider, FastifyBaseLogger> & { ...; }' is not assignable to type 'RouteOptions<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, any, any, any, FastifyTypeProviderDefault, FastifyBaseLogger> & { ...; }'.
Type 'RouteOptions<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, any, any, any, ZodTypeProvider, FastifyBaseLogger> & { ...; }' is not assignable to type 'RouteOptions<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, any, any, any, FastifyTypeProviderDefault, FastifyBaseLogger>'.
Types of property 'handler' are incompatible.
Type 'RouteHandlerMethod<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, any, any, any, ZodTypeProvider, FastifyBaseLogger>' is not assignable to type 'RouteHandlerMethod<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, any, any, any, FastifyTypeProviderDefault, FastifyBaseLogger>'.
Type 'FastifyTypeProviderDefault' is not assignable to type 'ZodTypeProvider'.
The error is shown both in onRequest
and preHandler
hooks. I should mention that the error does not show up if I remove the app.auth()
function and use the auth functions on their own or in an array.
Steps to Reproduce
Create a fastify server and install the mentioned packages along with zod
. Create two auth functions and try to use them in either onRequest
or preHandler
hooks.
export default async function routes(app: FastifyInstance) {
app
.withTypeProvider<ZodTypeProvider>()
.route({
method: 'GET',
url: '/',
schema: {
description: 'Get all users',
tags: ['User'],
response: {
200: userResponseSchema.array(),
},
},
onRequest: app.auth([app.authenticate, app.guard]),
handler: getUsersHandler,
});
}
Expected Behavior
I would like to use this package without this typescript error like this:
onRequest: app.auth([app.authenticate, app.guard])
I have no clue why this is happening unfortunately. A PR to fix would be awesome.
Great I will fork the repo and play around with the type definitions. If I come up with a fix I will add a PR. Thanks for the feedback!
Just want to update you on this. Apparently, this issue exists with other type providers as well as you can see in this issue on the fastify-type-provider-typebox package. It seems the problem is the return type of the fastify.auth([])
which is typed with the FastifyTypeProvider
and not the specific type provider used in the project. Unfortunately, I'm not that proficient in typescript to fix this so for now I will use the suggestion in the issue to add as any
wherever I use fastify.auth([])
.
I was poking around with index-test.d.ts
and found a few things:
The passing case:
jsonSchemaToTS.route({
method: 'GET',
url: '/with-param',
schema: {body: {type: 'object', properties: {param: {type: 'string'}}, required: ['param']}},
preHandler: jsonSchemaToTS.auth([]),
handler: (req) => {
expectType<{ param: string, [x: string]: unknown }>(req.body)
}
})
The failing case (req.body
is of type unknown
):
jsonSchemaToTS.get("/test", {
preHandler: jsonSchemaToTS.auth([]),
schema: { body: { type: 'object', properties: { param: { type: 'string' } }, required: ['param'] } },
}, (req) => {
expectType<{ param: string, [x: string]: unknown }>(req.body)
})
As mentioned by @geovla93, the failing case starts to work if we do preHandler: jsonSchemaToTS.auth([]) as any
Update: just found that this also works
jsonSchemaToTS.get("/test", {
preHandler: jsonSchemaToTS.auth([]),
schema: { body: { type: 'object', properties: { param: { type: 'string' } }, required: ['param'] } },
handler: (req) => {
expectType<{ param: string, [x: string]: unknown }>(req.body)
}
})
I was experiencing a similar issue with fastify-type-provider-json-schema-to-ts
where when the auth plugin was used in the preHandler, everything was resolving to unknown. I'm not quite sure what fixed it, but ensuring I was running 4.6.1 seemed to resolve the issue for me.