From a11152f42b281df83409313962f60f230239c79e Mon Sep 17 00:00:00 2001 From: Maxime Kjaer Date: Wed, 31 Mar 2021 11:37:37 +0200 Subject: [PATCH] fix(typings): add fallback to untyped event listener (#3834) Related: https://github.com/socketio/socket.io/issues/3833 --- lib/typed-events.ts | 22 +++++++++++++++++----- test/socket.io.test-d.ts | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/lib/typed-events.ts b/lib/typed-events.ts index 1d44ae2a..1a497844 100644 --- a/lib/typed-events.ts +++ b/lib/typed-events.ts @@ -43,11 +43,23 @@ export type ReservedOrUserListener< ReservedEvents extends EventsMap, UserEvents extends EventsMap, Ev extends ReservedOrUserEventNames -> = Ev extends EventNames - ? ReservedEvents[Ev] - : Ev extends EventNames - ? UserEvents[Ev] - : never; +> = FallbackToUntypedListener< + Ev extends EventNames + ? ReservedEvents[Ev] + : Ev extends EventNames + ? UserEvents[Ev] + : never +>; + +/** + * Returns an untyped listener type if `T` is `never`; otherwise, returns `T`. + * + * This is a hack to mitigate https://github.com/socketio/socket.io/issues/3833. + * Needed because of https://github.com/microsoft/TypeScript/issues/41778 + */ +type FallbackToUntypedListener = [T] extends [never] + ? (...args: any[]) => void + : T; /** * Interface for classes that aren't `EventEmitter`s, but still expose a diff --git a/test/socket.io.test-d.ts b/test/socket.io.test-d.ts index 7014ad52..22be5561 100644 --- a/test/socket.io.test-d.ts +++ b/test/socket.io.test-d.ts @@ -44,6 +44,38 @@ describe("server", () => { }); }); }); + + it("infers 'any' for listener parameters of other events using enums", () => { + const srv = createServer(); + const sio = new Server(srv); + srv.listen(() => { + sio.on("connection", (socket) => { + expectType>(socket); + }); + + enum Events { + CONNECTION = "connection", + TEST = "test", + } + + sio.on(Events.CONNECTION, (socket) => { + // TODO(#3833): Make this expect `Socket` + expectType(socket); + + socket.on("test", (a, b, c) => { + expectType(a); + expectType(b); + expectType(c); + }); + + socket.on(Events.TEST, (a, b, c) => { + expectType(a); + expectType(b); + expectType(c); + }); + }); + }); + }); }); describe("emit", () => {