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

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions