fastify / fastify-websocket

basic websocket support for fastify
MIT License
400 stars 74 forks source link

TypeProvider not working properly under Fastify v4 #213

Closed tajnymag closed 2 years ago

tajnymag commented 2 years ago

Prerequisites

Fastify version

4.2.1

Plugin version

6.0.1

Node.js version

16.13.2

Operating system

Windows

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

10

Description

Fastify-websocket seems to break TypeProvider typings in its WebsocketHandler. I am able to compile code with the official json-schema-to-ts type-provider. After enabling websocket: true in the route's options and changing the route's handler, the type inference vanishes.

In my example, the /websocket route fails to compile due to request.query being typed as unknown. It should behave the same way the handler in /http route does. To infer the query params and fail due to a type mismatch on the following line.

Steps to Reproduce

Try running this code with a modern typescript version. Reproducible even on TypeScript Playground (link to prepared playground)

Example (modified https://github.com/fastify/fastify-type-provider-json-schema-to-ts/issues/12)

import { JsonSchemaToTsProvider } from '@fastify/type-provider-json-schema-to-ts';
import fastifyWebsocket from '@fastify/websocket';

import fastify from 'fastify';

const server = fastify().withTypeProvider<JsonSchemaToTsProvider>();
server.register(fastifyWebsocket);

server.get(
    '/websocket',
    {
        websocket: true,
        schema: {
            querystring: {
                type: 'object',
                properties: {
                    foo: { type: 'number' },
                    bar: { type: 'string' },
                },
                required: ['foo', 'bar'],
            },
        } as const
    },
    (connection, request) => {
        const { bar } = request.query // should NOT fail
        bar.push('foo') // SHOULD fail
    }
);

server.get(
    '/http',
    {
        schema: {
            querystring: {
                type: 'object',
                properties: {
                    foo: { type: 'number' },
                    bar: { type: 'string' },
                },
                required: ['foo', 'bar'],
            },
        } as const
    },
    (request) => {
        const { bar } = request.query // should NOT fail
        bar.push('foo') // SHOULD fail
    }
);

Expected Behavior

Generally, the types should stay inferred like in any other http handler.

In my example, the route /websocket should have the same compilation error like the route /http. That means request.query should be correctly inferred to be an object of { foo, bar } and bar.push('foo') should fail as bar isn't an array.

airhorns commented 2 years ago

Agreed -- the types in fastify-websocket may need updating to properly proxy through the type provider when it infers the new route handler signature. Want to take a crack at a PR?

tajnymag commented 2 years ago

Sure. I just haven't understood the typings enough yet. I'll give it another look tomorrow.

teastman commented 2 years ago

I'm having the same issues, I'll try my hand at a PR.

tajnymag commented 2 years ago

The issue has been fixed by https://github.com/fastify/fastify-websocket/pull/225