Skip to content

TypeScript overload error soup when registering a route. #1110

@ClayCore

Description

@ClayCore

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

Image

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)

Metadata

Metadata

Assignees

No one assigned

    Labels

    help wantedExtra attention is needed

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions