New approach in Typescript: Enhancement of child class with additional Event Listener overloads

One of my classes is structured like this:

interface A extends EventEmitter{
    on(event: "eventA", listener: () => void): this;
}

There is another class defined as follows:

interface B extends A{
    on(event: "eventB", listener: () => void): this;
}

My intention is to utilize these classes in the following manner:

const foo = new B();
foo.on("eventA", listenerForA);
foo.on("eventB", listenerForB);

Note that it is not feasible to make any changes to Class A. When attempting to implement this, I encounter an Error message:

TS2415: Class 'B' incorrectly extends 'A'

PS: The declaration of both Class A and Class B is necessary, but they have been omitted here for clarity.

view code in TS playground

Edit: It has been suggested to replicate the overloads from the parent class. However, I am curious if there is an alternative method to achieve this without duplicating the overloads?

Thank you for any assistance provided.

Answer №1

After being inspired by the response provided by Фарид Ахмедов, I have crafted this piece of code that handles callback overloads as well:

interface B extends A{
    on(event: Parameters<A['on']>[0], listener: Parameters<A['on']>[1]): this;
    on(event: "eventB", listener: (bar: string) => void): this;
}

The initial overload simply replicates the existing ones.

By leveraging Parameters<...>, you can also incorporate multiple overloads for EventEmitter.emit().

Answer №2

Perhaps a different approach:

// Defining types based on event parameters
type EventFrom<T extends A> = Parameters<T['on']>[0]

interface A {
    on(event: "eventA"): this;
}

interface B extends A {
    on(event: "eventB" | EventFrom<A>): this; // eventA | eventB
}

interface C extends B {
    on(event: "eventC" | EventFrom<B>): this; // eventA | eventB | eventC
}

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

Unable to get the onchange event to trigger for a span element

Is there a way to trigger the onchange event on a span element that doesn't seem to be working? Here is the code I am using: Attempt 1 document.getElementById(seconds).addEventListener('change', (event: MutationEvent & { path: any }) =& ...

Changing a password on Firebase using Angular 5

I am in the process of developing a settings feature for user accounts on an application I've been working on. One key functionality I want to include is the ability for users to update their password directly from the account settings page. To enable ...

Using Angular 4 to retrieve a dynamic array from Firebase

I have a dilemma while creating reviews for the products in my shop. I am facing an issue with the button and click event that is supposed to save the review on the database. Later, when I try to read those reviews and calculate the rating for the product, ...

Leverage es6 classes along with mongoose in typescript to utilize loadClass functionality

I've been struggling with a problem and despite my exhaustive search on Google, I still haven't found a solution. My issue revolves around incorporating es6 classes with mongoose using the schema.loadClass(class) method. Unfortunately, when worki ...

Updating an array within a dynamic form using patchValue in Angular 4

My dynamic form, inspired by the Angular documentation, includes a feature that allows users to load their saved forms. I have encountered an issue where I am able to patch the values of text fields and radio buttons successfully, but I am facing difficu ...

The interface is unable to populate the Array of Elements

When using Angular, I send a request and save the response in a variable: conversations: Conversation[]; // ChatService getConversations() { return this.http.get<Conversation[]>('/chat/conversations'); } this.chatService.getConversat ...

Error in Docker: Unable to resolve due to sender error: context has been terminated

After attempting to build my docker image for the project in VS Code terminal, I ran into an error. What are some possible reasons for this issue? Along with this question, I have also shared a screenshot of the error logs. ERROR: failed to solve: error ...

What are the steps to successfully launch a Node.js / Express application with typescript on heroku?

I attempted to deploy my node.js / express server app on Heroku but encountered some issues. I followed the steps outlined in a blog post, which you can find here. Unfortunately, the deployment did not succeed. Below are snippets of the code from my serve ...

npm-bundle encounters an issue with Error: ENOENT when it cannot find the file or directory specified as 'package.json'

npm-bundle is throwing an error that says Error: ENOENT: no such file or directory, open 'package.json' in my NodeJs project. It works fine if I manually create test.js and package.json, then run npm install followed by npm-bundle. However, when ...

What distinguishes between the methods of detecting falsy and truthy values?

While working with JavaScript / Typescript, I often find myself needing to verify if a length exists or if a value is true or false. So, the main query arises: are there any differences in performance or behavior when checking like this... const data = [ ...

NEXT JS 13 experiencing an infinite loop when using State, encountering an error with Params, and facing issues with hook definition

Currently, I am in the process of developing a shopping cart using NEXT JS and encountering several issues within my code. To begin with, I have established a route [product]/[productitems] within the apps folder. In the page.tsx file of [productitems], I ...

I'm unable to modify the text within my child component - what's the reason behind this limitation?

I created a Single File Component to display something, here is the code <template> <el-link type="primary" @click="test()" >{{this.contentShow}}</el-link> </template> <script lang="ts"> imp ...

How to change a specific value in an array of objects using React

Within my array, I have objects containing the fields id and title const cols = [ { id: 0, title: "TODO" }, { id: 1, title: "InProgress" }, { id: 2, title: "Testing" }, { ...

The functionality for handling gestures on AgmMap appears to be non-functional

I am currently using the AGM Map feature available on and I need to disable the zooming functionality when scrolling. Despite setting gestureHandling = "'cooperative'", it does not seem to work. Are there any specific factors causing this issue? ...

Creating a Map in TypeScript from an Array

I have a series of TypeScript objects structured like this: interface MyObject { id: string, position: number } My goal is to transform this array into a map format where it shows the relationship between id and position, as needed for a future JSON ...

What is the best way to transfer props between components using typescript?

I have a unique button component that I need to include in another component. The button type and interface I am using are as follows: type IButton = { className?: string, onClick?: MouseEventHandler; children: React.ReactNode; props: IButt ...

Authentication of users using NextJS Dashboard App API

I am currently following this tutorial, but instead of fetching data via a PostgreSQL request, I want to utilize an API. When I call an async function with await, it initially returns undefined and then the user object after receiving a response from the ...

Tips for identifying the most effective element locator in the DOM with Playwright

Currently, I am in the process of incorporating Playwright tests for a website that supports multiple locales. The majority of the page content is dynamically generated from CMS content (Contentful). I am hesitant about using hardcoded text locators like ...

I encountered a MISSING_MESSAGE error while using the next-intl npm package in my next.js application

import { useEffect } from "react"; import type { AppProps } from "next/app"; import Script from "next/script"; import { SWRConfig } from "swr"; import { useRouter } from "next/router" import { AppContext } ...

Transforming a JavaScript component based on classes into a TypeScript component by employing dynamic prop destructuring

My current setup involves a class based component that looks like this class ArInput extends React.Component { render() { const { shadowless, success, error } = this.props; const inputStyles = [ styles.input, !shadowless && s ...