turkerdev / fastify-type-provider-zod

MIT License
337 stars 21 forks source link

Is type checking for responses possible? #25

Closed elie-h closed 1 year ago

elie-h commented 1 year ago

Just trying out the examples and it looks like it's not possible to type check responses except at runtime? Is there a way to implement this? For request params or the body it's possible using the generic: FastifyRequest<{ Querystring: CustomTypeHere }>

For example typescript doesn't pick up an error in mismatched types of what's defined and what's returned:

app.withTypeProvider<ZodTypeProvider>().route({
  method: "GET",
  url: "/",
  // Define your schema
  schema: {
    querystring: z.object({
      name: z.string().min(4),
    }),
    response: {
      200: z.string(),
    },
  },
  handler: (req, res) => {
    res.send(12345);
  },
});
kibertoad commented 1 year ago

~~See https://github.com/turkerdev/fastify-type-provider-zod/issues/16 It is possible and it is working, with the exception of primitive types (such as string in your case). It would work if you wrapped that string into some object.~~ nvm, you are looking for compile time check. not sure if that is possible

turkerdev commented 1 year ago

TS should catch the error in the example you provided in both compile time and VSCode

elie-h commented 1 year ago

It doesn't catch the error in compile time or VSCode - the types for the responses aren't inferred correctly for whatever is passed in the send() method. Unless I'm missing a setup step that's not in the docs?

elie-h commented 1 year ago

Restarting the ts server resolved the issue ... weird one but thanks for the help!

james-gardner commented 8 months ago

@turkerdev There's some behaviour here which I don't fully understand, just to add to this. In a plugin context I defined a type like this:

type FastifyPluginAsyncZod<Options extends FastifyPluginOptions = Record<never, never>, Server extends RawServerBase = RawServerDefault> = FastifyPluginAsync<Options, Server, ZodTypeProvider>;

Used like so:

export const ninjas: FastifyPluginAsyncZod<NinjaManagementOptions> = 
  async function (fastify, { repository }) {
      ...

I thought I was being smart by putting the above type in a global d.ts module but that prevents the path params from being type checked in my editor (VS Code). Likewise if I try and extend FastifyRequest with generics it stops the response type checking.

export const students: FastifyPluginAsyncZod<NinjaManagementOptions> = 
  async function (fastify, { repository }) {

    fastify.get('/:id', {
      schema: {
        params: ninjaPathParams, // <-- type errors when FastifyPluginAsyncZod is moved to global module. Becomes 'unknown'.
        response: {
          200: ninja // <-- type errors when I try and use generics with FastifyRequest.
        }
      }
    }, async function (request, reply) {
      const { uuid, dojoId } = request.params;

      const ninja = await repository.getById(uuid, dojoId);

      if (!ninja) {
        return reply.status(404).send();
      }

      reply.send(ninja);
    });

I'm sure this is just me getting muddled up with the generics and I'd like to get a firmer understanding of what's going on here. Any pointers?