Utilizing TypeScript's dynamic class method parameters

I've been working on integrating EventBus with TypeScript and I'm trying to create a dynamic parameter event in the emit method. How can I achieve this?

interface IEventBusListener {
  (...params: any[]): void
}

class EventBus {
  constructor(private listeners: Record<string | symbol, IEventBusListener[]> = {}) { }

  on(event: string | symbol, callback: IEventBusListener) {
    if (!this.listeners[event]) {
      this.listeners[event] = [];
    }

    this.listeners[event].push(callback);
  }

  off(event: string | symbol, callback: IEventBusListener) {
    if (!this.listeners[event]) {
      throw new Error(`Нет события: ${event.toString()}`);
    }

    this.listeners[event] = this.listeners[event].filter(
      listener => listener !== callback
    );
  }

  emit<T extends keyof typeof this.listeners>(event: T, ...args: any[]) {
    if (!this.listeners[event]) {
      throw new Event(`Нет события: ${event.toString()}`);
    }

    this.listeners[event].forEach(listener => {
      listener(...args);
    });
  }
}

I was hoping for autocomplete and type checking, but unfortunately it's not functioning as expected.

https://i.sstatic.net/3pZRu.png

Answer №1

To effectively handle event callbacks, it is important to establish a clear map of relations between event names and their corresponding parameters. Take the following example:

class EventDispatcher<P extends Record<string, any[]>> {
    on<E extends keyof P>(eventName: E, callback: (...args: P[E]) => void) {
        // Implement logic here
    }
}

type EventTypeMap = {
    'click': [number]
    'hover': [string]
}
class EventHandler extends  EventDispatcher<EventTypeMap> {

}

const handler = new EventHandler();

Alternatively, consider using the eventemitter3 library for advanced functionality.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The positioning of CSS arrows using the "top" attribute is not relative to the top of the page when using absolute values

I am currently working on positioning the arrow in the screenshot using TypeScript calculations. However, I am facing an issue where the position is being determined based on the top of the black popup instead of the top of the screen. From the top of the ...

Switching slides in Ionic 4 with a simple button click

I want to switch slides by clicking a button on my presentation. Here is an example code snippet: <ion-slides> <ion-slide> Slide one <ion-slide> <ion-slide> Slide Two <ion-slide> </ion-slides> <butt ...

Generate a type error if the string does not correspond to the key of the object

How can I trigger a type error in TypeScript 4.4.3 for the incorrect string 'c' below, which is not one of the keys of the object that is passed as the first parameter to the doSomething method? const doSomething = ({ a, b }: { a: number, b: stri ...

Updating ComboBox Selection in Angular 4

When attempting to populate a combobox with the value from a selected row, only the inputs are loading. This section is part of my page: ` <form class="form-horizontal form-label-left parsleyjs" method="post" data-parsley-priority-enabled="false" n ...

Issue with MongoDB $push within an Array of Arrays: The shorthand property 'elements' does not have a value available in scope

I am encountering an issue while trying to insert data into Elements in MongoDB using TypeScript. Any suggestions on how to resolve this problem? Attempt 1 Error: I am receiving an error message stating "No value exists in scope for the shorthand property ...

Finding the number of elements in a FirebaseListObservable involves accessing the `length` property

One of the tasks in my Angular 2 application involves retrieving data from a Firebase database and storing it in a FirebaseListObservable. I have a method called getStatus that is supposed to determine the number of elements in this FirebaseListObservable. ...

After compiling, global variables in Vue.js 2 + Typescript may lose their values

I am currently working on a Vue.js 2 project that uses Typescript. I have declared two variables in the main.ts file that I need to access globally throughout my project: // ... Vue.prototype.$http = http; // This library is imported from another file and ...

What is the best way to get both the id and name of a selected item in Angular?

Within my select field, data is dynamically populated based on names. My objective is to not only capture the selected name but also its corresponding ID. Here's a snippet of my HTML template: <select class="custom-select d-block w-100" id="test" ...

Creating a hyperlink to a subdomain in TypeScript Execution File

I am seeking to add a link directing to a subdomain in the navigation bar of a react theme. Although I feel a bit hesitant about asking for help on something seemingly simple, I have struggled to find any relevant examples online to assist me. Below is the ...

Unreliable TypeScript errors when using spread arguments

Consider this function: function foo(a: number, b: number) {/* ... */} Error is triggered by Snippet 1: foo(1, ...[]); Expected 2 arguments, but received only 1. Error is triggered by Snippet 2: foo(1, 2, ...[]); Expected 2 arguments, but rece ...

On a mobile device, the keyboard is hiding the PrimeNG dropdown

While my dropdown works flawlessly on a desktop browser, I encountered an issue when accessing it on an Android device. The dropdown immediately disappears and the virtual keyboard pops up, which is not the case on iOS devices. I suspect that the problem ...

``Implementing a method to save the output of an asynchronous request in a global variable for future manipulation

It's been a week and I still can't figure this out. Being new to front-end development, I'm struggling with storing the response from subscribe in a global variable for future use. ngOnInit(): void { this.http.get<APIResponse>('ur ...

Expand the font manually

Is there a way to define a type that represents the widened version of another type? Consider the following scenario: function times<A extends number, B extends number>(a: A, b: B): A & B; The intention behind this times function is to preserv ...

An error was encountered at line 7800, character 18 in the three-core.d.ts file in the node_modules/@types/three directory. The error message reads: "Cannot find name 'VRDisplay

I encountered an error in my Angular 6 app while running ng serve ERROR in node_modules/@types/three/three-core.d.ts(7800,18): error TS2304: Cannot find name 'VRDisplay'. node_modules/@types/three/three-core.d.ts(7801,23): error TS2304: Canno ...

Explain the object type that is returned when a function accepts either an array of object keys or an object filled with string values

I've written a function called getParameters that can take either an array of parameter names or an object as input. The purpose of this function is to fetch parameter values based on the provided parameter names and return them in a key-value object ...

Is there support for TypeScript in express-openid-connect?

Is there any documentation available for using express-openid-connect with TypeScript, or if it is supported at all? ...

Encountering an issue saving files in Angular 2 when the npm server is active

Encountering an issue when trying to save .ts or .html files while npm is running 1: DoJoin(aka DoJoin) [native array.js:~129] [pc=0000035BB365DBB2] (this=0000005A3F604381 <undefined>,w=000003CB8840CFF1 <JS Array[104]>,x=104,N=0000005A3F6 ...

The router.navigate() function seems to be malfunctioning as it is not working as

I have a method defined as follows: private redirect(path: string): void { this.router.navigate([path]); } This method is called within another method like so: private onError(error: any): void { switch (error.status) { case 401: / ...

Is there a way to automate downloading a file in Angular using the browser's built-in download feature?

When I make a request to my webservice to download a zip file, the file content is downloaded secretly and suddenly appears in the download task bar as already fully downloaded (100%). I am using the following method in Angular: const endpoint = "http:// ...

How should one properly assign an element type provided as an argument?

I'm attempting to define a type for an element passed as a parameter using React.ComponentType. import * as React from "react" type BaseType = { element: React.ComponentType } const Base = ({element: Element}: BaseType) => ( <Ele ...