Freeze object when emitting
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
export type EventMap = Record<string, unknown>;
|
export type EventMap = Record<string, unknown>;
|
||||||
|
|
||||||
type Listener<T> = (detail: T) => void;
|
type Listener<T> = (detail: Readonly<T>) => void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internally permits listeners for individual event payloads to be stored
|
* Internally permits listeners for individual event payloads to be stored
|
||||||
@@ -72,7 +72,7 @@ export class EventEmitter<T extends EventMap> {
|
|||||||
* @returns An off callback that can be called to stop listening for events.
|
* @returns An off callback that can be called to stop listening for events.
|
||||||
*/
|
*/
|
||||||
once<K extends keyof T>(type: K, listener: Listener<T[K]>, debounceMilliseconds?: number): OffCallback {
|
once<K extends keyof T>(type: K, listener: Listener<T[K]>, debounceMilliseconds?: number): OffCallback {
|
||||||
const wrappedListener: Listener<T[K]> = (detail: T[K]) => {
|
const wrappedListener: Listener<T[K]> = (detail: Readonly<T[K]>) => {
|
||||||
this.off(type, listener);
|
this.off(type, listener);
|
||||||
listener(detail);
|
listener(detail);
|
||||||
};
|
};
|
||||||
@@ -131,9 +131,12 @@ export class EventEmitter<T extends EventMap> {
|
|||||||
const listeners = this.listeners.get(type);
|
const listeners = this.listeners.get(type);
|
||||||
if (!listeners) return false;
|
if (!listeners) return false;
|
||||||
|
|
||||||
|
// Freeze the payload to make it readonly.
|
||||||
|
const readonlyPayload = Object.freeze(payload);
|
||||||
|
|
||||||
// Emit the event to all listeners.
|
// Emit the event to all listeners.
|
||||||
listeners.forEach((entry) => {
|
listeners.forEach((entry) => {
|
||||||
entry.wrappedListener(payload);
|
entry.wrappedListener(readonlyPayload);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Return true if there are listeners for the event, false otherwise.
|
// Return true if there are listeners for the event, false otherwise.
|
||||||
@@ -154,13 +157,13 @@ export class EventEmitter<T extends EventMap> {
|
|||||||
* @param timeoutMs - The timeout in milliseconds.
|
* @param timeoutMs - The timeout in milliseconds.
|
||||||
* @returns The event payload.
|
* @returns The event payload.
|
||||||
*/
|
*/
|
||||||
async waitFor<K extends keyof T>(type: K, predicate: (payload: T[K]) => boolean, timeoutMs?: number): Promise<T[K]> {
|
async waitFor<K extends keyof T>(type: K, predicate: (payload: Readonly<T[K]>) => boolean, timeoutMs?: number): Promise<Readonly<T[K]>> {
|
||||||
// Create a promise to wait for the event to be emitted.
|
// Create a promise to wait for the event to be emitted.
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
let timeoutId: ReturnType<typeof setTimeout> | undefined;
|
||||||
|
|
||||||
// Create a listener function.
|
// Create a listener function.
|
||||||
const listener = (payload: T[K]): void => {
|
const listener = (payload: Readonly<T[K]>): void => {
|
||||||
if (predicate(payload)) {
|
if (predicate(payload)) {
|
||||||
// Clean up
|
// Clean up
|
||||||
this.off(type, listener);
|
this.off(type, listener);
|
||||||
@@ -195,7 +198,7 @@ export class EventEmitter<T extends EventMap> {
|
|||||||
// Create a timeout variable.
|
// Create a timeout variable.
|
||||||
let timeout: ReturnType<typeof setTimeout>;
|
let timeout: ReturnType<typeof setTimeout>;
|
||||||
|
|
||||||
return (detail: T[K]) => {
|
return (detail: Readonly<T[K]>) => {
|
||||||
// If a debounce timer is already pending, clear it before scheduling the next one.
|
// If a debounce timer is already pending, clear it before scheduling the next one.
|
||||||
if (timeout !== undefined) {
|
if (timeout !== undefined) {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
|
|||||||
Reference in New Issue
Block a user