fastify-type-provider-typebox: preHandler types conflict with package `@fastify/auth`

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.0.0-rc.3

Plugin version

No response

Node.js version

16.x

Operating system

Linux

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

Ubuntu 20.04

Description

I’m having TypeScript issues in the route preHandler when the package @fastify/auth ^3.0.0 is being used altogether. I’m unsure if this an issue of that package or this, but I’ve began experiencing issues once .withTypeProvider<TypeBoxTypeProvider>() is called. The error received:

Type 'preHandlerHookHandler<Server, IncomingMessage, ServerResponse, RouteGenericInterface, unknown, FastifySchema, FastifyTypeProviderDefault, ResolveFastifyRequestType<...>, FastifyLoggerInstance>' is not assignable to type 'preHandlerHookHandler<Server, IncomingMessage, ServerResponse, RouteGenericInterface, unknown, FastifySchema, TypeBoxTypeProvider, ResolveFastifyRequestType<...>, FastifyLoggerInstance> | preHandlerHookHandler<...>[] | undefined'.

Steps to Reproduce

Install fastify@4, @fastify/auth@3 and .1.0-beta.1 version of this plugin in a TypeScript environment. Calling the fastify.auth([]) in the route preHandler will give a type error.

Expected Behavior

No response

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 19 (13 by maintainers)

Most upvoted comments

@mcollina @TheWashiba Hi. Had a brief look at this the other day. The issue appears to be caused by the server.auth([]) function returning a function signature that is globally typed to use the FastifyTypeProvider (not the TypeBoxTypeProvider as configured). As such the assignment of server.auth([]) on the preHandler is the primary source of this type error as the Provider types are incompatible (as mentioned by @fox1t )

Unfortunately, because the auth() function is globally typed (using module augmentation here), and because the plugin is patching the auth() function at runtime on the fastify instance, there doesn’t appear to be many options available to resolve the local typing at the provider, as TypeScript is unaware of any type modifications made by the patch.

Workaround

In the interim, the following should offer a workaround if using Type Providers (albeit a not ideal solution with the any). @TheWashiba this code was derived from your repro repository. You can preview the typing on this located here.

import { Type } from '@sinclair/typebox'
import { TypeBoxTypeProvider } from '@fastify/type-provider-typebox'
import fastifyAuth from '@fastify/auth'
import fastify from 'fastify'
import fp from 'fastify-plugin'

// --------------------------------------------------------------------------------
// Plugin
// --------------------------------------------------------------------------------

export const plugin = fp(
  (fastify) => {
    const instance = fastify.withTypeProvider<TypeBoxTypeProvider>();

    instance.route({
      method: 'GET',
      url: '/plugin',
      schema: {
        body: Type.Object({
          a: Type.Number(),
          b: Type.Number()
        })
      },
      preHandler: instance.auth([]) as any, // todo: review global module augmentation of the server auth() function.
      handler: async (req, res) => { 
        const { a, b } = req.body 
      },
    });
  },
  {
    name: 'example',
  }
);

// --------------------------------------------------------------------------------
// Index
// --------------------------------------------------------------------------------

const server = fastify().withTypeProvider<TypeBoxTypeProvider>();
server.register(fastifyAuth);
server.register(plugin)
server.route({
  method: 'GET',
  url: '/',
  schema: {
    body: Type.Object({
      x: Type.Number(),
      y: Type.Number()
    })
  },
  preHandler: server.auth([]) as any, // todo: review global module augmentation of the server auth() function.
  handler: async (req, res) => {
    const { x, y } = req.body
  },
});

Possible Next Steps

I think probably the best way forward is spending some time taking a look at the way the current server.auth([]) function definitions (potentially avoiding global module augmentation if possible). I think any investigations into this would likely be applicable for other plugin modules that augment the underlying FastifyInstance. So would make for good documentation for plugin authors writing TS definitions.

In terms of TypeScript, the ideal way to allow types to propagate would be to chain calls to register(), as follows.

const server = fastify()
 .withTypeProvider<TypeBoxTypeProvider>() // remap to generic TypeBoxTypeProvider
 .register(fastifyAuth)                   // augment instance with `.auth()` function.
 .register(plugin)                        // augment with user defined functionality.
 .route({                                 // route: configured with the above
   method: 'GET',
   url: '/',
   schema: {
     body: Type.Object({
       x: Type.Number(),
       y: Type.Number()
     })
   },
   preHandler: server.auth([]),
   handler: a sync (req, res) => {
     const {  x, y } = req.body
   }
  });

Although there may be additional options to explore with the following PR’s

https://github.com/fastify/fastify/pull/3952 - Global augmentation of FastifyTypeProviderDefault https://github.com/fastify/fastify/pull/4034 - Propagate generics from FastifyRegister

Hope that helps! S

thx, I’ll take a look asap

cc @fastify/typescript could you take a look?