From 460cc9faf4352f9fd205a678132ea66914fd8852 Mon Sep 17 00:00:00 2001 From: Richard Herman <1429781+GeekyEggo@users.noreply.github.com> Date: Mon, 21 Oct 2024 19:18:19 +0100 Subject: [PATCH] fix: event arg types (#63) * fix: event arg types * chore: fix linting --------- Co-authored-by: Richard Herman --- src/common/__tests__/event-emitter.test.ts | 58 +++++++++++++++++++++- src/common/event-emitter.ts | 27 ++-------- 2 files changed, 62 insertions(+), 23 deletions(-) diff --git a/src/common/__tests__/event-emitter.test.ts b/src/common/__tests__/event-emitter.test.ts index ec249339..4c5434c1 100644 --- a/src/common/__tests__/event-emitter.test.ts +++ b/src/common/__tests__/event-emitter.test.ts @@ -1,4 +1,5 @@ -import { EventEmitter } from "../event-emitter"; +import type { Expect, TypesAreEqual } from "../../../tests/utils"; +import { type EventArgs, EventEmitter, type EventsOf } from "../event-emitter"; describe("EventEmitter", () => { describe("adding listeners", () => { @@ -363,10 +364,65 @@ describe("EventEmitter", () => { expect(two).toHaveBeenCalledWith("Hello world"); }); }); + + /* eslint-disable @typescript-eslint/no-unused-vars */ + describe("types", () => { + /** + * Event map + */ + test("event map", () => { + // @ts-expect-error: arguments of type `string` are not valid + const invalidArgs = new EventEmitter<{ + invalid: string; + valid: [name: string]; + }>(); + + // @ts-expect-error: key of type `Number` is not valid. + const invalidEventName = new EventEmitter<{ + [1]: [name: string]; + valid: [name: string]; + }>(); + }); + + /** + * Event names. + */ + test("event name", () => { + type eventName = Expect< + TypesAreEqual, "another" | "array" | "empty" | "message" | "other" | (string & {})> + >; + + // @ts-expect-error: arguments of type `string` are not valid + type invalid = EventsOf<{ + invalid: string; + valid: [name: string]; + }>; + }); + + /** + * Event arguments. + */ + it("events args", () => { + type t = EventArgs; + + type empty = Expect, []>>; + type single = Expect, [message: string]>>; + type multiple = Expect, [id: number, name: string]>>; + + type invalid = EventArgs< + // @ts-expect-error: arguments of type `string` are not valid + { invalid: string }, + "invalid" + >; + }); + }); + /* eslint-enable @typescript-eslint/no-unused-vars */ }); type EventMap = { message: [message: string]; other: [id: number]; another: [id: number]; + empty: []; + array: [id: number, name: string]; }; diff --git a/src/common/event-emitter.ts b/src/common/event-emitter.ts index 2f24ac98..0be2bc8a 100644 --- a/src/common/event-emitter.ts +++ b/src/common/event-emitter.ts @@ -240,32 +240,15 @@ type EventMap = { /** * Parsed {@link EventMap} whereby each property is a `string` that denotes an event name, and the associated value type defines the listener arguments. */ -export type EventsOf = - EventMap extends T - ? string - : keyof EventMap< - Pick< - T, - Extract< - { - [K in keyof T]: K extends string ? K : never; - }[keyof T], - { - [K in keyof T]: T[K] extends unknown[] ? K : never; - }[keyof T] - > - > - >; +export type EventsOf> = keyof TMap | (string & {}); /** * Parses the event arguments for the specified event from the event map. */ -type EventArgs = TMap extends { - [k in TEvent]: infer TArgs; -} - ? TArgs extends [unknown] - ? TArgs - : unknown[] +export type EventArgs, TEvent extends EventsOf> = TEvent extends keyof TMap + ? TMap[TEvent] extends unknown[] + ? TMap[TEvent] + : never : unknown[]; /**