Skip to content

Commit

Permalink
feat(emitter generic type): adds generic to keep track of state expected
Browse files Browse the repository at this point in the history
  • Loading branch information
mdxprograms committed May 8, 2023
1 parent 58a289a commit 6f61c43
Show file tree
Hide file tree
Showing 9 changed files with 1,124 additions and 7,266 deletions.
5 changes: 2 additions & 3 deletions lib/emitter.test.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { describe, it, expect } from "vitest";
import Emitter from "./emitter";

const emit = new Emitter();

const emit = new Emitter<{ name: string }>();
const NameSent = "name:sent";

describe("emitter tests", () => {
it("should receive { name: 'John' }", async () => {
const onNameSent = emit.on(NameSent);
const handleNameSent = emit.dispatch(NameSent);

onNameSent(({ name }: { name: string }) => {
onNameSent(({ name }) => {
expect(name).toBe("John");
});

Expand Down
30 changes: 16 additions & 14 deletions lib/emitter.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,37 @@
type Listener = (args: any) => void;
import { Listener, Listeners } from "./types/Emitter";

export default class Emitter {
events: Record<string, Listener[]>;
export default class Emitter<T> {
private listeners: Listeners<T>

constructor() {
this.events = {};
this.listeners = {};
}

hasEvent(eventName: string) {
return Object.keys(this.events).includes(eventName);
return Object.keys(this.listeners).includes(eventName);
}

isCallback(callback: Listener): boolean {
isCallback(callback: Listener<T>): boolean {
return typeof callback === "function";
}

isValidEventName(eventName: string): boolean {
return typeof eventName === "string";
}

removeListener(eventName: string, callbackListener: Listener): void {
removeListener(eventName: string, callbackListener: Listener<T>): void {
if (!this.hasEvent(eventName)) {
throw Error(`${eventName} does not exist`);
}

this.events[eventName] = this.events[eventName].filter(
(listener: Listener) =>
this.listeners[eventName] = this.listeners[eventName].filter(
(listener: Listener<T>) =>
listener.toString() !== callbackListener.toString()
);
}

on(eventName: string) {
return (callback: Listener) => {
return (callback: Listener<T>) => {
if (!this.isCallback(callback)) {
throw Error(`${typeof callback} must be a function`);
}
Expand All @@ -41,22 +41,24 @@ export default class Emitter {
}

if (!this.hasEvent(eventName)) {
this.events[eventName] = [];
this.listeners[eventName] = [];
}

this.events[eventName].push(callback);
this.listeners[eventName].push(callback);
};
}

dispatch(eventName: string) {
return (payload: Record<string, unknown>) => {
return (payload: T) => {
if (!this.hasEvent(eventName)) {
throw Error(`${eventName} is not a registered event`);
}

this.events[eventName].forEach((listener: Listener) => {
this.listeners[eventName].forEach((listener: Listener<T>) => {
listener(payload);
});
};
}
}

export type EmitterType = typeof Emitter
2 changes: 2 additions & 0 deletions lib/mycelia.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ export type {
elementNames,
} from "./types/DOM";
export type { Mount } from "./types/Utils";
export type { EmitterType } from "./emitter";
export type { Listener, Listeners } from "./types/Emitter";
3 changes: 3 additions & 0 deletions lib/types/Emitter.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export type Listener<T> = (value: T) => any;

export type Listeners<T> = Record<string, Listener<T>[]>
Loading

0 comments on commit 6f61c43

Please sign in to comment.