From e1d392e2a724a0d68046981478f60f5fce7f93b7 Mon Sep 17 00:00:00 2001 From: Tony133 Date: Thu, 1 Oct 2026 10:10:32 +0200 Subject: [PATCH] fix(types): type handler as websocket handler in route() with websocket: true --- types/index.d.ts | 13 ++++++++++- types/index.tst.ts | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index c56983c..46149ea 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -34,10 +34,21 @@ declare module 'fastify' { type InjectWSFn = ((path?: string, upgradeContext?: Partial, options?: InjectWSOption) => Promise) - // eslint-disable-next-line @typescript-eslint/no-unused-vars interface FastifyInstance { websocketServer: WebSocket.Server, injectWS: InjectWSFn + + // When `websocket: true` is set, `handler` is the websocket handler, so type it as such + route< + RouteGeneric extends RouteGenericInterface = RouteGenericInterface, + ContextConfig = ContextConfigDefault, + const SchemaCompiler extends FastifySchema = FastifySchema + >( + opts: Omit, 'handler' | 'websocket'> & { + websocket: true, + handler: fastifyWebsocket.WebsocketHandler + } + ): FastifyInstance; } interface FastifyRequest { diff --git a/types/index.tst.ts b/types/index.tst.ts index afdc0da..5169465 100644 --- a/types/index.tst.ts +++ b/types/index.tst.ts @@ -129,6 +129,48 @@ app.route<{ } }) +app.route({ + method: 'GET', + url: '/route-full-declaration-syntax-websocket', + websocket: true, + handler: async function (socket, request) { + expect(this).type.toBe() + expect(socket).type.toBe() + expect(request).type.toBe>() + expect(request.ws).type.toBe() + } +}) + +app.route({ + method: 'GET', + url: '/route-full-declaration-syntax-not-websocket', + websocket: false, + handler: (request, reply) => { + expect(request).type.toBe() + expect(reply).type.toBe() + } +}) + +app.route<{ + Params: { foo: string }; + Body: { bar: string }; + Querystring: { search: string }; + Headers: { auth: string }; +}>({ + method: 'GET', + url: '/longhand-explicit-types-websocket', + websocket: true, + handler: (socket, request) => { + expect(socket).type.toBe() + expect(request.params).type.toBe<{ foo: string }>() + expect(request.body).type.toBe<{ bar: string }>() + expect(request.query).type.toBe<{ search: string }>() + expect(request.headers).type.toBe< + IncomingMessage['headers'] & { auth: string } + >() + } +}) + const schema = { params: Type.Object({ foo: Type.String() }, { required: ['foo'] }), querystring: Type.Object({ search: Type.String() }, { required: ['search'] }), @@ -187,6 +229,22 @@ server.get( } ) +server.route({ + method: 'GET', + url: '/longhand-type-inference-websocket', + schema, + websocket: true, + handler: (socket, request) => { + expect(socket).type.toBe() + expect(request.params).type.toBe<{ foo: string }>() + expect(request.body).type.toBe<{ bar: string }>() + expect(request.query).type.toBe<{ search: string }>() + expect(request.headers).type.toBe< + IncomingMessage['headers'] & { auth: string } + >() + } +}) + expect(namedFastifyWebsocket).type.toBe(fastifyWebsocket) expect(fastifyWebsocket).type.toBe(fastifyWebsocket)