Skip to content

Commit

Permalink
fix: event arg types (#63)
Browse files Browse the repository at this point in the history
* fix: event arg types

* chore: fix linting

---------

Co-authored-by: Richard Herman <[email protected]>
  • Loading branch information
GeekyEggo and GeekyEggo authored Oct 21, 2024
1 parent f2ae57f commit 460cc9f
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 23 deletions.
58 changes: 57 additions & 1 deletion src/common/__tests__/event-emitter.test.ts
Original file line number Diff line number Diff line change
@@ -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", () => {
Expand Down Expand Up @@ -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<EventsOf<EventMap>, "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<EventMap, "array">;

type empty = Expect<TypesAreEqual<EventArgs<EventMap, "empty">, []>>;
type single = Expect<TypesAreEqual<EventArgs<EventMap, "message">, [message: string]>>;
type multiple = Expect<TypesAreEqual<EventArgs<EventMap, "array">, [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];
};
27 changes: 5 additions & 22 deletions src/common/event-emitter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,32 +240,15 @@ type EventMap<T> = {
/**
* 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<T> =
EventMap<unknown> 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<TMap extends EventMap<TMap>> = keyof TMap | (string & {});

/**
* Parses the event arguments for the specified event from the event map.
*/
type EventArgs<TMap, TEvent extends string> = TMap extends {
[k in TEvent]: infer TArgs;
}
? TArgs extends [unknown]
? TArgs
: unknown[]
export type EventArgs<TMap extends EventMap<TMap>, TEvent extends EventsOf<TMap>> = TEvent extends keyof TMap
? TMap[TEvent] extends unknown[]
? TMap[TEvent]
: never
: unknown[];

/**
Expand Down

0 comments on commit 460cc9f

Please sign in to comment.