Subclass callback with parameters

Having some trouble with one of my TypeScript functions and I'm hoping it's not a silly question. I believe what I'm attempting should work in theory.

Here's a simplified version of my issue to demonstrate where the problem lies (the original code is too lengthy).

abstract class A {
    name: string;

    log(callback: (ev: A) => void) {}

    constructor(name: string) {
        this.name = name;
    }
}

class B extends A {
    addr: string;

    constructor(addr: string, name: string) {
        super(name);
        this.addr = addr;
    }
}

let b = new B("1", "2");

b.log((ev: B) => {});

The issue arises in the last line of code. The log function is a callback with type A, but I am trying to call it with an attribute of type B. This should theoretically work because B extends A, but I'm getting the following error:

Argument of type '(ev: B) => void' is not assignable to parameter of type '(ev: A) => void'.
  Types of parameters 'ev' and 'ev' are incompatible.
    Property 'addr' is missing in type 'A' but required in type 'B'.(2345)
input.tsx(13, 5): 'addr' is declared here.

I'd rather not cast my ev parameter in the function. Hopefully, you understand the issue and my objectives.

Have a wonderful day.

Answer №1

This error is related to the concept of contravariance.

Imagine you have a method log in a class A, defined as:

abstract class A {
    // ...
    log(ev: A) { console.log(ev.name) };
    //...
}

You can call this method with an instance of class B, like this:

let b = new B("1", "2");
b.log(b); // this works because `B` also has a property `name`

An example can be found here.

However, when you try to pass a function with signature (ev: A) => void to a function that expects (ev: B) => void, issues arise. For instance, a function with the signature (ev: B) => void might look like this:

function (ev: B) {
    console.log(ev.addr); // Accessing a `B` specific property
}

This function would fail if you pass an object of type A to it because A does not have the property addr</code, only <code>B does. TypeScript prevents this for type safety reasons.

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

Creating a JSON object in JavaScript using an array

Can anyone assist me with the following code snippet for formatting the current month? var monthNames = ['jan', 'fev', 'mar', 'abr', 'mai', 'jun', 'jul', 'ago', 'set&apos ...

Modify the CSS class dynamically by clicking a button (using class names stored in an array)

How can I dynamically change a CSS class on button press while using an array of class names? When I hard code the classes in a switch statement, everything works fine. However, when trying to pull class names from an array, it jumps to the end of the swit ...

An unexpected error occurred in the Ember route processing: Assertion Failed in the listing

After working diligently to integrate an Emberjs front end (utilizing Ember Data) with my Flask API backend, I have encountered a puzzling issue. Despite the adapter functioning correctly - as evidenced by the API being called when accessing the 'List ...

Tips for extracting individual keys from an object and transferring them into a separate object

I have an array of objects containing all the form data. However, I need to format this data differently before sending it to the backend. Each object needs to be fetched separately and then pushed into another object as shown below. The current data looks ...

Error encountered while attempting to cast value "xxxxxx" to ObjectId in the "item" model, resulting in a CastError

I've been struggling to resolve an error while trying to delete a todo from a page using findByIdAndRemove and findByIdAndDelete methods. Despite researching and attempting various solutions, the error persists. Any assistance would be greatly appreci ...

What steps should I take to ensure that a cookie has been properly set before utilizing it?

I'm in the process of developing a JWT authorization code flow using Next.js and NestJS. Below is the POST request being sent from the frontend to the backend server: const response = await fetch( 'http://localhost:4000/auth/42/callback?code=& ...

Issue: AngularJS not refreshing view after receiving server response

Currently, as I work on developing a mobile application, I've come across an issue related to relaying messages in the view after executing an ajax call and receiving data from the server. My goal is to display these messages to users only after they ...

When using `npm publish`, any files located within the `node_modules

After developing an npm package, I included some modules in the node_modules directory to make them accessible as "modules". For instance, I have a module called my-module.js in node_modules which I require in my code using require('my-module'). ...

Tips for executing a function when nearing the bottom of a scroll:

I have incorporated the angular2-infinite-scroll plugin, specifically version 0.1.4. You can view my plunker here. Currently, the function onScrollDown() only runs once at the beginning when scrolling. I attempted to adjust the values for infiniteScroll ...

Having trouble getting Jquery autocomplete to function properly with a complicated array?

I started with the guidance provided in this post, which was successful. To investigate why it's not functioning, I made a JsFiddle but couldn't figure out the issue. Even when trying to search for results using the first letter of the last name ...

Changing the font family for a single element in Next.js

One unique aspect of my project is its global font, however there is one element that randomly pulls font families from a hosted URL. For example: https://*****.com/file/fonts/Parnian.ttf My page operates as a client-side rendered application (CSR). So, ...

What is the best way to implement a required input field in Vue.js?

I need some assistance with my chat functionality. I want to prevent users from sending empty messages, so I want to make the input field required. Can you please help me with this? I have already tried adding "required='required'" to the input ...

Choosing Tags with Ajax in Select2

The JSON data below is fetched from /tags: [ { "id": "CSS", "text": "CSS" }, { "id": "HTML", "text": "HTML" }, { "id": "JavaScript", "text": "JavaScript" }, { "id": "jQuer ...

Mastering typing properties in React with TypeScript

Could someone please help me with this issue? I have created a basic react component. interface iRowData{ name: string } export default function ResultsSection(data: iRowData[]) { return <div>Results</div> } When I try to use it in ano ...

Encountering an issue in Angular 8 where a class is not being added after the page loads, resulting in an

Looking to dynamically add a class to a div element using Angular? I have a condition isTrue, and am utilizing the angular function ngAfterViewInit() to add the class hideOnLoad after the page loads when isTrue becomes true. Instead of traditional javascri ...

Changing JavaScript functions into jQuery functions

Currently, I have this Javascript function that I am interested in converting to jQuery: function confirm() { var http = new XMLHttpRequest(); var url = "index.php?tag=' . $dt . '"; var params = "confirm_ref=' . urlencode(encry ...

Disabling Scrolling in AngularJS Material Tab Components

I'm experimenting with AngularJS Material components and struggling with creating tabs. Every time I add a tab, the content inside the child md-content element automatically gets a fixed height with a vertical scrollbar instead of adjusting its heigh ...

Is it possible to modify the CSS styling in React using the following demonstration?

I am attempting to create an interactive feature where a ball moves to the location where the mouse is clicked. Although the X and Y coordinates are being logged successfully, the ball itself is not moving. Can anyone help me identify what I might be overl ...

What is causing my axios request to not retrieve the correct data?

My axios instance is set up to connect to an API that has a login route. When I test the API using Postman, everything works perfectly and it returns JWT access and refresh tokens for valid credentials. However, when I try to login through my app using axi ...

What is the process for converting an Angular UTC timestamp to a local timestamp?

Is it possible to convert a UTC timestamp to a local time timestamp using any function or method? I am sending the timestamp to angular moments, but the server's timestamp is in UTC. ...