Question
After being inspired by this template and liking how the routes are organized, I tried to implement the following routing structure.
export interface IRouter {
path: string;
getRoutes: (fastify: FastifyInstance, options: RouteOptions) => Promise<void>;
}
It's used to implement "routers" containing multiple route like so:
import { FastifyInstance as Instance, RouteOptions as Options } from "fastify";
import { FastifyRequest as Request, FastifyReply as Reply } from "fastify";
import type { IRouter } from "../types.js";
export class GreetRouter implements IRouter {
public path = "/greet";
public async getRoutes(fastify: Instance, options: Options) {
fastify.post(this.path, async function (request: Request<{ Body: { name: string } }>, reply: Reply) {
const { name } = request.body;
const message = `Hello ${name}`;
return reply.send({ message });
});
}
}
That interface allows me to define implementations, which contain multiple routes defined with a shorthand such as fastify.post and fastify.get and later collect them and register them all at once, with options such as the prefix.
import { FastifyInstance as Instance, FastifyPluginOptions as Options } from "fastify";
import fp from "fastify-plugin";
import { IndexRouter } from "./routers/index.js";
import { GreetRouter } from "./routers/greet.js";
import type { IRouter } from "./types.js";
const routes = fp(async (fastify: Instance, options: Options) => {
const routers: Array<IRouter> = [new IndexRouter(), new GreetRouter()];
routers.forEach((router: IRouter) => {
fastify.log.info(`registering router for ${router.path}`);
fastify.register(router.getRoutes.bind(router), { prefix: "/api/v1" });
});
});
export default routes;
All the code in the MRE runs perfectly fine in watch mode when using bun run dev
However, when attempting to build the project with tsc I get the following
Error log when transpiling the project with tsc
$ tsc --build .
src/router.ts:21:22 - error TS2769: No overload matches this call.
Overload 1 of 6, '(plugin: FastifyPluginCallback): FastifyInstance<...> & ... 1 more ... & { ...; }', gave the following error.
Argument of type '(fastify: FastifyInstance, FastifyBaseLogger, FastifyTypeProviderDefault>, options: RouteOptions<...>) => Promise<...>' is not assignable to parameter of type 'FastifyPluginCallback'.
Types of parameters 'options' and 'opts' are incompatible.
Type 'FastifyPluginOptions' is missing the following properties from type 'RouteOptions, RouteGenericInterface, unknown, FastifySchema, FastifyTypeProviderDefault, FastifyBaseLogger>': method, url, handler
Overload 2 of 6, '(plugin: FastifyPluginAsync): FastifyInstance<...> & ... 1 more ... & { ...; }', gave the following error.
Argument of type '(fastify: FastifyInstance, FastifyBaseLogger, FastifyTypeProviderDefault>, options: RouteOptions<...>) => Promise<...>' is not assignable to parameter of type 'FastifyPluginAsync'.
Types of parameters 'options' and 'opts' are incompatible.
Type 'FastifyPluginOptions' is missing the following properties from type 'RouteOptions, RouteGenericInterface, unknown, FastifySchema, FastifyTypeProviderDefault, FastifyBaseLogger>': method, url, handler
Overload 3 of 6, '(plugin: FastifyPluginCallback | FastifyPluginAsync<...> | Promise<...> | Promise<...>): FastifyInstance<...> & ... 1 more ... & { ...; }', gave the following error.
Argument of type '(fastify: FastifyInstance, FastifyBaseLogger, FastifyTypeProviderDefault>, options: RouteOptions<...>) => Promise<...>' is not assignable to parameter of type 'FastifyPluginCallback | FastifyPluginAsync<...> | Promise<...> | Promise<...>'.
Type '(fastify: FastifyInstance, FastifyBaseLogger, FastifyTypeProviderDefault>, options: RouteOptions<...>) => Promise<...>' is not assignable to type 'FastifyPluginCallback'.
Types of parameters 'options' and 'opts' are incompatible.
Type 'FastifyPluginOptions' is missing the following properties from type 'RouteOptions, RouteGenericInterface, unknown, FastifySchema, FastifyTypeProviderDefault, FastifyBaseLogger>': method, url, handler
21 fastify.register(router.getRoutes.bind(router));
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To my understanding, I'm providing the correct signature when registering the route, but according to this error, RouteOptions and FastifyPluginOptions are incompatible (which I'm not arguing against).
I don't exactly know how to merge or make these types overlap to make this work even when building and I don't really want to cast the plugin callback to any. I'd love to know where have I gone wrong with types.
MRE
note that in the MRE the { prefix: "/api/v1" } was not added to the options, but the error remains the same.
available here: https://github.com/ClayCore/fastify-type-error
Your Environment
- node version: 24.6.0
- bun version: 1.2.19
- fastify version: ^5.5.0
- typescript version: ^5
- os: Linux CachyOS (6.16.3-2-cachyos)
Question
After being inspired by this template and liking how the routes are organized, I tried to implement the following routing structure.
It's used to implement "routers" containing multiple route like so:
That interface allows me to define implementations, which contain multiple routes defined with a shorthand such as
fastify.postandfastify.getand later collect them and register them all at once, with options such as theprefix.All the code in the MRE runs perfectly fine in watch mode when using
bun run devHowever, when attempting to build the project with
tscI get the followingError log when transpiling the project with tsc
$ tsc --build . src/router.ts:21:22 - error TS2769: No overload matches this call. Overload 1 of 6, '(plugin: FastifyPluginCallback): FastifyInstance<...> & ... 1 more ... & { ...; }', gave the following error. Argument of type '(fastify: FastifyInstance, FastifyBaseLogger, FastifyTypeProviderDefault>, options: RouteOptions<...>) => Promise<...>' is not assignable to parameter of type 'FastifyPluginCallback'. Types of parameters 'options' and 'opts' are incompatible. Type 'FastifyPluginOptions' is missing the following properties from type 'RouteOptions, RouteGenericInterface, unknown, FastifySchema, FastifyTypeProviderDefault, FastifyBaseLogger>': method, url, handler Overload 2 of 6, '(plugin: FastifyPluginAsync): FastifyInstance<...> & ... 1 more ... & { ...; }', gave the following error. Argument of type '(fastify: FastifyInstance, FastifyBaseLogger, FastifyTypeProviderDefault>, options: RouteOptions<...>) => Promise<...>' is not assignable to parameter of type 'FastifyPluginAsync'. Types of parameters 'options' and 'opts' are incompatible. Type 'FastifyPluginOptions' is missing the following properties from type 'RouteOptions, RouteGenericInterface, unknown, FastifySchema, FastifyTypeProviderDefault, FastifyBaseLogger>': method, url, handler Overload 3 of 6, '(plugin: FastifyPluginCallback | FastifyPluginAsync<...> | Promise<...> | Promise<...>): FastifyInstance<...> & ... 1 more ... & { ...; }', gave the following error. Argument of type '(fastify: FastifyInstance, FastifyBaseLogger, FastifyTypeProviderDefault>, options: RouteOptions<...>) => Promise<...>' is not assignable to parameter of type 'FastifyPluginCallback | FastifyPluginAsync<...> | Promise<...> | Promise<...>'. Type '(fastify: FastifyInstance, FastifyBaseLogger, FastifyTypeProviderDefault>, options: RouteOptions<...>) => Promise<...>' is not assignable to type 'FastifyPluginCallback'. Types of parameters 'options' and 'opts' are incompatible. Type 'FastifyPluginOptions' is missing the following properties from type 'RouteOptions, RouteGenericInterface, unknown, FastifySchema, FastifyTypeProviderDefault, FastifyBaseLogger>': method, url, handler21 fastify.register(router.getRoutes.bind(router));
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
To my understanding, I'm providing the correct signature when registering the route, but according to this error,
RouteOptionsandFastifyPluginOptionsare incompatible (which I'm not arguing against).I don't exactly know how to merge or make these types overlap to make this work even when building and I don't really want to cast the plugin callback to
any. I'd love to know where have I gone wrong with types.MRE
note that in the MRE the
{ prefix: "/api/v1" }was not added to the options, but the error remains the same.available here: https://github.com/ClayCore/fastify-type-error
Your Environment