Skip to content

Commit

Permalink
Add type tests for listeners and event streams
Browse files Browse the repository at this point in the history
And ensure they deal with events that don't have data just fine!
  • Loading branch information
airhorns committed Dec 28, 2020
1 parent 8d03436 commit 809522a
Show file tree
Hide file tree
Showing 2 changed files with 114 additions and 30 deletions.
14 changes: 7 additions & 7 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ type DatalessEventNames<EventData> = {
[Key in keyof EventData]: EventData[Key] extends undefined ? Key : never;
}[keyof EventData];


/**
Emittery is a strictly typed, fully async EventEmitter implementation. Event listeners can be registered with `on` or `once`, and events can be emitted with `emit`.
Expand Down Expand Up @@ -326,11 +325,12 @@ declare class Emittery<
@returns A method to unsubscribe.
*/
onAny(
listener: <Name extends keyof EventData>(
eventName: Name,
eventData?: EventData[Name]
listener: (
eventName: keyof EventData,
eventData: EventData[keyof EventData]
) => void
): Emittery.UnsubscribeFn;

/**
Get an async iterator which buffers a tuple of an event name and data each time an event is emitted.
Expand Down Expand Up @@ -373,9 +373,9 @@ declare class Emittery<
Remove an `onAny` subscription.
*/
offAny(
listener: <Name extends keyof EventData>(
eventName: Name,
eventData?: EventData[Name]
listener: (
eventName: keyof EventData,
eventData: EventData[keyof EventData]
) => void
): void;

Expand Down
130 changes: 107 additions & 23 deletions index.test-d.ts
Original file line number Diff line number Diff line change
@@ -1,55 +1,139 @@
import {expectType, expectError} from 'tsd';
import Emittery = require('.');
import { expectType, expectError } from "tsd";
import Emittery = require(".");

// emit
{
const ee = new Emittery();
ee.emit('anEvent');
ee.emit('anEvent', 'some data');
ee.emit("anEvent");
ee.emit("anEvent", "some data");
}

// on
{
const ee = new Emittery();
ee.on('anEvent', () => undefined);
ee.on('anEvent', () => Promise.resolve());
ee.on('anEvent', data => undefined);
ee.on('anEvent', data => Promise.resolve());
ee.on(Emittery.listenerAdded, ({eventName, listener}) => {});
ee.on(Emittery.listenerRemoved, ({eventName, listener}) => {});
const off = ee.on('anEvent', () => undefined);
ee.on("anEvent", () => undefined);
ee.on("anEvent", () => Promise.resolve());
ee.on("anEvent", data => undefined);
ee.on("anEvent", data => Promise.resolve());
ee.on(Emittery.listenerAdded, ({ eventName, listener }) => {});
ee.on(Emittery.listenerRemoved, ({ eventName, listener }) => {});
const off = ee.on("anEvent", () => undefined);
off();
}

// off
{
const ee = new Emittery();
ee.off('anEvent', () => undefined);
ee.off('anEvent', () => Promise.resolve());
ee.off('anEvent', data => undefined);
ee.off('anEvent', data => Promise.resolve());
ee.off("anEvent", () => undefined);
ee.off("anEvent", () => Promise.resolve());
ee.off("anEvent", data => undefined);
ee.off("anEvent", data => Promise.resolve());
}

{
const ee = new Emittery();
expectError(ee.emit('anEvent', 'some data', 'and more'));
expectError(ee.emit("anEvent", "some data", "and more"));
}

{
const ee = new Emittery();
expectError(ee.on('anEvent', (data: any, more: any) => undefined));
expectError(ee.on("anEvent", (data: any, more: any) => undefined));
}

// Strict typing
// Strict typing for emission
{
const ee = new Emittery<{
value: string;
open: undefined;
close: undefined;
}>();
ee.emit('open');
ee.emit('close');
ee.emit('value', 'test');
expectError(ee.emit('value'));
expectError(ee.emit('open', 'test'));
ee.emit("open");
ee.emit("close");
ee.emit("value", "test");
expectError(ee.emit("value"));
expectError(ee.emit("open", "test"));
}

// Strict typing for listeners
{
const ee = new Emittery<{
value: string;
open: undefined;
close: undefined;
}>();
ee.on("open", () => {});
ee.on("open", argument => {
expectType<undefined>(argument);
});

ee.on("value", () => {});
ee.on("value", argument => {
expectType<string>(argument);
});

const listener = (value: string) => undefined;
ee.on("value", listener);
ee.off("value", listener);
ee.once("value").then(listener);

expectError(ee.on("value", (value: number) => {}));
}

// Strict typing for onAny, offAny listeners
{
const ee = new Emittery<{
value: string;
open: undefined;
close: undefined;
other: number;
}>();

ee.onAny((name, data) => {
expectType<"value" | "open" | "close" | "other">(name);
expectType<string | number | undefined>(data);
});

const listener = (name: string) => {};
ee.onAny(listener);
ee.offAny(listener);
}

// Strict typing for onAny, offAny listeners for an Emittery that only has listeners with arguments
{
const ee = new Emittery<{
value: string;
other: number;
}>();

ee.onAny((name, data) => {
expectType<"value" | "other">(name);
expectType<string | number>(data);
});
}

// Strict typing for anyEvent iterator
{
const testAnyEvent = async () => {
const ee = new Emittery<{
value: string;
open: undefined;
close: undefined;
}>();

for await (const event of ee.anyEvent()) {
expectType<"value" | "open" | "close">(event[0]);

expectType<string | undefined>(event[1]);
}

const ee2 = new Emittery<{
value: string;
other: number;
}>();

for await (const event of ee2.anyEvent()) {
expectType<"value" | "other">(event[0]);
expectType<string | number>(event[1]);
}
};
}

0 comments on commit 809522a

Please sign in to comment.