Skip to content

Instances with type-providers are not assignable to FastifyInstance #4342

@driimus

Description

@driimus

Prerequisites

  • I have written a descriptive issue title
  • I have searched existing issues to ensure the bug has not already been reported

Fastify version

4.7.0

Plugin version

No response

Node.js version

18.1.0

Operating system

Linux

Operating system version (i.e. 20.04, 11.3, 10)

Ubuntu 20.04.5 LTS

Description

Fastify instances with an enabled type-provider are not subtypes of the base FastifyInstance interface.

Example

A fastify server with type-providers enabled will not be usable as input for the @fastify/aws-lambda plugin, which expects a FastifyInstance parameter.

export default function awsLambdaFastify<TEvent, TResult = LambdaResponse>(
  app: FastifyInstance,
  options?: LambdaFastifyOptions
): PromiseHandler<TEvent, TResult>;

Cause

A more detailed explanation can be found in the reproduction repo.

In short, the assignability issue stems from certain methods of FastifyInstance being contravariant on TypeProvider. Because of that, the compiler has to flip the assignability check's direction, which boils down to the following outcome:

Types of property 'handler' are incompatible.
  Type 'RouteHandlerMethod<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, ... 4 more ..., FastifyBaseLogger>' is not assignable to type 'RouteHandlerMethod<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, any, any, any, FastifyTypeProviderDefault, FastifyBaseLogger>'.
    Types of parameters 'request' and 'request' are incompatible.
      Type 'FastifyRequest<any, RawServerDefault, IncomingMessage, any, FastifyTypeProviderDefault, any, FastifyBaseLogger, ResolveFastifyRequestType<...>>' is not assignable to type 'FastifyRequest<any, Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, any, TypeBoxTypeProvider, any, FastifyBaseLogger, ResolveFastifyRequestType<...>>'.
        Type 'ResolveFastifyRequestType<FastifyTypeProviderDefault, any, any>' is not assignable to type 'ResolveFastifyRequestType<TypeBoxTypeProvider, any, any>'.
+          Type 'FastifyTypeProviderDefault' is not assignable to type 'TypeBoxTypeProvider'.

Steps to Reproduce

  1. Check out the Minimal reproduction repo, which uses the "@fastify/aws-lambda": "^3.1.3" plugin.
  2. Install dependencies
  3. Run pnpm tsc --noEmit to check for type errors
  4. Notice the assignability error

From the CI run: https://github.com/driimus/fastify-instance-assignability/actions/runs/3259362782/jobs/5352129645#step:6:11

Error: src/index.ts([27](https://github.com/driimus/fastify-instance-assignability/actions/runs/3259362782/jobs/5352129645#step:6:28),41): error TS2769: No overload matches this call.
  Overload 1 of 2, '(app: FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>, options?: LambdaFastifyOptions | undefined): PromiseHandler<...>', gave the following error.
    Argument of type 'FastifyInstance<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, TypeBoxTypeProvider>' is not assignable to parameter of type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>'.
      The types returned by 'after()' are incompatible between these types.
        Type 'FastifyInstance<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, TypeBoxTypeProvider> & PromiseLike<...>' is not assignable to type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault> & PromiseLike<...>'.
          Type 'FastifyInstance<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, TypeBoxTypeProvider> & PromiseLike<...>' is not assignable to type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>'.
            Types of property 'register' are incompatible.
              Type 'FastifyRegister<FastifyInstance<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, TypeBoxTypeProvider> & PromiseLike<...>, RawServerDefault, FastifyTypeProvider>' is not assignable to type 'FastifyRegister<FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault> & PromiseLike<...>, RawServerDefault, FastifyTypeProvider>'.
                Type 'FastifyInstance<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, TypeBoxTypeProvider> & PromiseLike<...>' is not assignable to type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault> & PromiseLike<...>'.
                  Type 'FastifyInstance<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, TypeBoxTypeProvider> & 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("/home/runner/work/fastify-instance-assignability/fastify-instance-assignability/node_modules/.pnpm/fastify@4.8.1/node_modules/fastify/types/route").RouteGenericInterface = import("/home/runner/work/fastify-instance-assignability/fastify-instance-assignability/node_modules/.pnpm/fastif...' is not assignable to type '{ <RouteGeneric extends import("/home/runner/work/fastify-instance-assignability/fastify-instance-assignability/node_modules/.pnpm/fastify@4.8.1/node_modules/fastify/types/route").RouteGenericInterface = import("/home/runner/work/fastify-instance-assignability/fastify-instance-assignability/node_modules/.pnpm/fastif...'. 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<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, ... 4 more ..., FastifyBaseLogger> & { ...; }' is not assignable to type 'RouteOptions<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, any, any, any, FastifyTypeProviderDefault, FastifyBaseLogger> & { ...; }'.
                              Type 'RouteOptions<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, ... 4 more ..., FastifyBaseLogger> & { ...; }' is not assignable to type 'RouteOptions<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, any, any, any, FastifyTypeProviderDefault, FastifyBaseLogger>'.
                                Types of property 'handler' are incompatible.
                                  Type 'RouteHandlerMethod<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, ... 4 more ..., FastifyBaseLogger>' is not assignable to type 'RouteHandlerMethod<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, any, any, any, FastifyTypeProviderDefault, FastifyBaseLogger>'.
                                    Types of parameters 'request' and 'request' are incompatible.
                                      Type 'FastifyRequest<any, RawServerDefault, IncomingMessage, any, FastifyTypeProviderDefault, any, FastifyBaseLogger, ResolveFastifyRequestType<...>>' is not assignable to type 'FastifyRequest<any, Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, any, TypeBoxTypeProvider, any, FastifyBaseLogger, ResolveFastifyRequestType<...>>'.
                                        Type 'ResolveFastifyRequestType<FastifyTypeProviderDefault, any, any>' is not assignable to type 'ResolveFastifyRequestType<TypeBoxTypeProvider, any, any>'.
                                          Type 'FastifyTypeProviderDefault' is not assignable to type 'TypeBoxTypeProvider'.
  Overload 2 of 2, '(app: FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>, options?: LambdaFastifyOptions | undefined): CallbackHandler<...>', gave the following error.
    Argument of type 'FastifyInstance<Server<typeof IncomingMessage, typeof ServerResponse>, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, TypeBoxTypeProvider>' is not assignable to parameter of type 'FastifyInstance<RawServerDefault, IncomingMessage, ServerResponse<IncomingMessage>, FastifyBaseLogger, FastifyTypeProviderDefault>'.

Expected Behavior

I would expect specialised versions of the FastifyInstance interface, such as the ones using a custom type provider, to be assignable to FastifyInstance.

I am aware of some available workarounds:

  1. Extracting the type-provider enabled instance into a separate reference (similar to the scoped type-provider docs suggestion).
  2. Extending affected function signatures to include generic parameters which are propagated to their input argument of type FastifyInstance.

However, both of them seem inferior to ensuring that subtypes of FastifyInstance are assignable to the base interface.
I haven't look at the way type providers are being used in details, but it seems possible: 77b7582...driimus:fastify:test/type-provider-contravariance

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions