From 40b2f5cace99b06bb991b55d2f12dbec07eaab25 Mon Sep 17 00:00:00 2001 From: sunrise30 Date: Thu, 6 May 2021 11:53:57 +0200 Subject: [PATCH] fix(typings): add fallback to untyped event listener See also: https://github.com/socketio/socket.io/commit/a11152f42b281df83409313962f60f230239c79e Related: - https://github.com/socketio/socket.io/issues/3885 - https://github.com/socketio/socket.io/issues/3872 - https://github.com/socketio/socket.io/issues/3833 --- lib/typed-events.ts | 22 +++++++++++++++++----- test/typed-events.test-d.ts | 20 ++++++++++++++++++++ 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/lib/typed-events.ts b/lib/typed-events.ts index a6c73d3..4294e44 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; /** * Strictly typed version of an `EventEmitter`. A `TypedEventEmitter` takes type diff --git a/test/typed-events.test-d.ts b/test/typed-events.test-d.ts index f6ad59d..b2cadab 100644 --- a/test/typed-events.test-d.ts +++ b/test/typed-events.test-d.ts @@ -31,6 +31,26 @@ describe("typed events", () => { expectType(c); }); }); + + it("infers 'any' for listener parameters of other events using enums", () => { + const socket = io(); + + enum Events { + TEST = "test", + } + + 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", () => {