TypeScript: custom signatures for events in a subclass of EventEmitter

Within my programming project, I have a foundational class called EventEmitter, equipped with the on method for attaching handlers to specific events:

class EventEmitter {
    on(event: string, handler: Function) {
        /* internally add new handler */
    }

    protected emit(event: string, ...args) {
        /* trigger all event handlers listening on specified event */
    }
}

Now, in my various subclasses, each may need to emit different events with unique arguments. I want a way to explicitly define which events should be emitted by a particular subclass:

class MyClass extends EventEmitter {
    on(event: 'event1', handler: (arg1: number) => void): void;
    on(event: 'event2', handler: (arg1: string, arg2: number) => void): void;
}

However, when trying to implement this approach, TypeScript (tsc 1.8) raises errors:

error TS2415: Class 'MyClass' incorrectly extends base class 'EventEmitter'.
  Types of property 'on' are incompatible.
Type '(event: "event1", handler: (arg1: number) => void) => void' is not assignable to type '(event: string, handler: Function) => void'.
  Type '(event: "event1", handler: (arg1: number) => void) => void' does not match the signature '(event: string, handler: Function): void'
error TS2382: Specialized overload signature is not compatible with non-specialized signature.
error TS2391: Missing function implementation following declaration.

Therefore, I am searching for an alternative method to specify the events that my subclass can emit.

EDIT: After researching, I stumbled upon the term Specialized Signatures, but it appears to be designed for interfaces only, not suitable for implementing in new TypeScript code.

Further exploration led me to a related question from 2015 in another forum thread. However, the suggested solution offered there seemed inadequate. Are there any other contemporary approaches to handle this issue effectively in TypeScript?

Answer №1

How can I specify the events that my class can emit in a more organized way?

Instead of using one large stream of events containing all types, it is simpler to create individual event streams for each type.

I refer to this concept as TypedEvent. An example project utilizing this approach can be found at

To see the implementation, visit: https://github.com/alm-tools/alm/blob/55a8eb0f8ee411a506572abce92085235658b980/src/common/events.ts#L20-L72

An example of how this is used can be seen here: https://github.com/alm-tools/alm/blob/55a8eb0f8ee411a506572abce92085235658b980/src/server/lang/errorsCache.ts#L10

export let errorsUpdated = new TypedEvent<ErrorsUpdate>();
// emit: 
errorsUpdated.emit({} /* type checked */);
// consume:
errorsUpdated.on((x)=>null); // x has correct inferred type

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

Type 'Object' cannot be assigned to type 'Produit' as per error code TS2322

As a newcomer to Angular, I've been encountering the following error for the past 5 days: "ERROR in src/app/modifier-produit/modifier-produit.component.ts(23,7): error TS2322: Type 'Object' is not assignable to type 'Produit'. Th ...

Steps for importing jQuery to vendor.ts in Angular 2 webpack

Currently, I am in the process of setting up my Angular 2 app using webpack. As I review the vendor.ts file, I notice this specific structure. // Angular 2 import '@angular/platform-browser'; import '@angular/platform-browser-dynamic'; ...

Transform a string into a boolean value for a checkbox

When using v-model to show checked or unchecked checkboxes, the following code is being utilized: <template v-for="(item, index) in myFields"> <v-checkbox v-model="myArray[item.code]" :label="item.name" ...

Encountering difficulty importing TypeScript files dynamically within a Deno executable

When attempting to import a file from aws in an exe using its public link based on user input, I am facing difficulties For example, I generated my exe with the command below deno compile --allow-all main.ts Users execute this exe using commands like ./e ...

Setting character limits when defining string variables in TypeScript

Upon reviewing the documentation, it appears that there is no straightforward method to perform type checking for the minimum and maximum length of a string data type. However, is there a possible way to define a string data type using custom types in ord ...

Validating a single field name with various DTO types based on conditions in a NestJS application

There is a field named postData in EmailTypeDto, but it has different types based on conditions. It may be confusing to explain in words, but the code makes it clear. export class EmailTypeDto { @IsEnum(EmailType) public type: EmailType; @ValidateIf ...

Using TypeScript to deserialize various types from a shared object

I am currently dealing with a JSON array containing serialized objects, each of which has a type field. My challenge lies in deserializing them properly due to TypeScript not cooperating as expected: Check out the TypeScript playground for reference. type ...

leveraging services in Angular 4's router system

Below is the route setup: export const routes: Routes = [ {path: '', redirectTo: '/login', pathMatch: 'full'}, {path: 'login', component: LoginComponent, canActivate: [dbs.ConfigGuard]}, {path: '**& ...

A guide on selecting the best UI container based on API data in React using TypeScript

I have been developing a control panel that showcases various videos and posts sourced from an API. One div displays video posts with thumbnails and text, while another shows text-based posts. Below is the code for both: <div className=""> &l ...

TS2531: Nullability detected in object when using .match() method

I'm encountering a linting error on fileNameMatches[0] in the following code snippet. Strangely, the error doesn't appear on the Boolean() check. Even if I remove that check, the issue remains unresolved. Can anyone suggest a solution? protected ...

Encountering a 405 Error While Trying to Detect Location in Angular 7

I encountered an error 405 (Method Not Allowed) when trying to detect the location. Service public fetchWeatherDataByCoordinates(coordinates: ICoordinates): void { console.log("problem here") this.selectedLocationId.next(this.currentCoordinates ...

Exploring the integration of LeafLet into Next JS 13 for interactive mapping

I'm currently working on integrating a LeafLet map component into my Next JS 13.0.1 project, but I'm facing an issue with the rendering of the map component. Upon the initial loading of the map component, I encountered this error: ReferenceError ...

Building secure and responsive routes using next.js middleware

After setting up my routes.ts file to store protected routes, I encountered an issue with dynamic URLs not being properly secured. Even though regular routes like '/profile' were restricted for unauthenticated users, the dynamic routes remained a ...

Issue with Angular: Child component not receiving data after successful parent component call

I'm currently working with a parent and child component setup. Within the child component, I have a button configured like this: //child.component.html <button mat-raised-button [disabled]="!form.valid || submitButtonDisable" type = 'Submi ...

In TypeScript, the constructor parameter is automatically inferred as type "any"

Let's dissect the code snippet provided below: class Person { private name: string; constructor(name){ this.name = name; } } let p = new Person(5) The above code does not result in any errors. One would expect an error to occur ...

Tips for validating dates in Angular 4

Recently, I have started working with Angular and in my application I am facing a challenge regarding date validation. I need to validate a date input and display an error message based on the validation criteria. To achieve this, I am utilizing ngx-boots ...

Learn the process of typing a property that will be displayed as a dynamic HTML element component

Looking for a way to render an HTML element dynamically based on a prop in a React component? interface ButtonProps { children: ReactNode; className?: string; as?: string; <--- ? [key: string]: unknown; } const Button = forwardRef({ children, ...

Generating a dynamic table using Angular

My goal is to populate a table dynamically using the code below: teams.component.ts import { Component, OnInit } from '@angular/core'; import { first } from 'rxjs/operators'; import { TeamService } from 'src/app/services/team.ser ...

Sign in and create an account seamlessly on a single page with React

Looking for a way to integrate login and register functionalities on one page using React with TypeScript. However, facing an issue where the login component briefly displays before switching back to the signup component. Unable to determine why the stat ...

Create a TypeScript function that takes multiple functions as parameters and returns a union type consisting of the return values of each function

Would greatly appreciate any assistance with adding types to the following JavaScript function in TypeScript. I've been trying to solve this without resorting to using 'any' for an entire day with no luck. Here's the JavaScript functio ...