The cause of Interface A improperly extending Interface B errors in Typescript

Why does extending an interface by adding more properties make it non-assignable to a function accepting the base interface type? Shouldn't the overriding interface always have the properties that the function expects from the Base interface type?

There are many questions on StackOverflow about this issue, but none of them explain why it happens, why it's supposed to be like this, or how to fix the error with the expected outcome.

Since 2017, there has been an open Github issue thread on the same topic - TS Proposal : "Interface incorrectly extends interface" - sub-interface method overload OR override ?

Where is my understanding of extended interfaces incorrect?

Please assist a newcomer TS developer!!! Thanks...

// ------------------------ Types Declaration ----------------

interface ServerRequest {
    url: string,
    method: string,
    body: string | undefined
}

interface ExtendedServerRequest extends ServerRequest {
    orignal_url: string | undefined
}

type FunctionOrignal = (req: ServerRequest)=> void
type FunctionOverridden = (req: ExtendedServerRequest)=> void

interface ShortHandOptions {
    onSend: FunctionOrignal
}

interface ExtendedShortHandOptions extends ShortHandOptions {
    onSend: FunctionOverridden
}

// ------------------------ Test ----------------------------

console.log('------------------------------------------------');

function test(opts: ShortHandOptions) {
    opts.onSend({
        url: 'https://httpbin.org/get',
        method: 'GET'
    } as ServerRequest);
}

var func1: FunctionOrignal = (req) => {
        console.log('FunctionOrignal', req.url);
    },
    func2: FunctionOverridden = (req) => {
        console.log('FunctionOverridden', req.orignal_url);
    };

test({ onSend: func1 } as ShortHandOptions);

test({ onSend: func2 } as ExtendedShortHandOptions);

This results in:-

Interface 'ExtendedShortHandOptions' incorrectly extends interface 'ShortHandOptions'.
  Types of property 'onSend' are incompatible.
    Type 'FunctionOverridden' is not assignable to type 'FunctionOrignal'.
      Types of parameters 'req' and 'req' are incompatible.
        Property 'orignal_url' is missing in type 'ServerRequest' but required in type 'ExtendedServerRequest'.

This should work as long as test function calls onSend with an argument of type ShortHandOptions, i.e. an argument with at least the following properties { url, method, body }.

Answer №1

Your demonstration is nearly accurate. When you input ExtendedServerRequest as

orignal_url?: string

instead of

orignal_url: string | undefined

everything should function as expected. Playground Connection

Reasoning

According to the TS compiler, there exists a distinction between defining a property as optional using ? or declaring a necessary property that may also be undefined, which you have done.

Because orignal_url can be undefined but is compulsory, you are unable to convert ShortHandOptions into ExtendedShortHandOptions as depicted in your scenario.

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

CSS responsive design: concealing elements does not prevent the page from being displayed

Imagine a scenario where I need to display a template in two different versions based on the user's device. For instance, I have utilized the following code: <div class="desktop"> <body> Hi Desktop user </body> </div> ...

Issue with updating bound property correctly when dynamically generating components using v-for in Vue.js

Encountered a challenge with vue.js and seeking guidance on the best approach to address it. Here's a concise summary of the issue: Situation Data is fetched from a rest API, handled by a class called DataLoader using javascript prototype syntax. Th ...

Using JavaScript and HTML, create a click event that triggers a drop-down text

Can anyone help me with creating a dropdown feature using JavaScript, HTML, and CSS? I want to be able to click on the name of a project and have information about that project show up. Any suggestions on how I can achieve this? Thanks in advance! ...

Creating custom designs for Material UI components

Although not a major issue, there is something that bothers me. I am currently using react, typescript, and css modules along with . The problem arises when styling material ui components as I find myself needing to use !important quite frequently. Is th ...

Does each imported module in a Next.js app run multiple times?

There is a common understanding that when a module is imported multiple times within a JavaScript program, it only executes once during the first import. Informative article: The concept is straightforward: each module is evaluated just once, meaning th ...

Using TypeScript to create a generic type that wraps around HTMLElements

I attempted to execute this action, however the assignment to this.element is not working and I am unsure why. class Elem<T> { public element : T; constructor(typeElement:string){ this.element = document.createElement(typeElement); ...

Mastering the art of Promises and handling errors

I've been tasked with developing a WebApp using Angular, but I'm facing a challenge as the project involves Typescript and asynchronous programming, which are new to me. The prototype already exists, and it includes a handshake process that consi ...

Issues with Parameters in JavaScript Functions

I have been researching online and every website I visit suggests that a function would take a parameter if declared, but for some reason it's not working in my case. It works fine like this: <script type='text/javascript'> function ...

Shifting attention from the main point to the surrounding details (including siblings)

In my search bar layout, the main parent component consists of three child components - location dropdown, date picker (calendar), and duration dropdown. By default, the user's location is pre-selected in the location dropdown. I want the focus to shi ...

Issues arise when attempting to alter the background image using jQuery without browserSync being activated

I am facing an issue with my slider that uses background-images and BrowserSync. The slider works fine when BrowserSync is running, but without it, the animations work properly but the .slide background image does not appear at all. Can someone help me ide ...

Facing unexpected behavior with rxjs merge in angular5

import { Observable } from 'rxjs/Observable'; import 'rxjs/add/observable/merge'; this.data = this.itemsCollection.valueChanges() this.foo = this.afs.collection<Item>('products') .doc('G2loKLqNQJUQIsDmzSNahlopOyk ...

Inconsistent Animation Issue with jQuery Toggle for Expanding Div and Text

My expanding div functionality is almost perfect, but I've noticed that the transition when opening abruptly on divs with text. However, the closing transition is smooth. Can anyone help me make the opening transition as smooth as the closing one? Bel ...

Recording Audio Using ReactJS

I am exploring ways to record audio using ReactJS and save it on my Node server. Initially, I attempted to utilize the "react-audio-recorder" module but encountered issues when attempting to record multiple audios consecutively. Additionally, I experiment ...

Are there any guidelines or rules outlining what is still considered valid JSONP?

I am looking for information on how to properly parse JSONP messages in .NET and extract the JSON data they contain. Is there a current specification that outlines what constitutes a valid JSONP message? During my research, I came across a blog post from ...

Leveraging backstretch.js in combination with blur.js (or equivalent)

Query Update I provided a response to the query below, however, I am experiencing some lag and a noticeable stepped transition between images. Can anyone offer advice on how to optimize this issue? Perhaps it would be better to go back to using a static ...

Activate a button on-the-fly

When the page loads, I have an empty array. Since there are no values stored in this array, I disabled the button using ng-disabled="array1.length==0". Now, on the page that opens up, there are four drop downs present. My goal is to enable the button once ...

Steps to bring life to your JavaScript counter animation

I need to slow down the counting of values in JavaScript from 0 to 100, so that it takes 3 seconds instead of happening instantly. Can anyone help me with this? <span><span id="counter"> </span> of 100 files</span> <s ...

"Can you provide instructions on placing a span within an image

I am trying to figure out how to insert a <span> into an <image>, similar to the effect on the page . However, I do not want this effect to occur on hover(), but rather on click(). My goal is to insert "data-title" into the <span> and hav ...

Using a function from one class within another class by passing it as a prop

Below are the methods found in my Search.tsx class. renderSuggestion(suggestion) { <div className="buttons"> <button className="button">View Location</button> <button className="button whitebutton" onClick={this.h ...

Exploring JSON data and making precise adjustments in JavaScript

I am attempting to create my own database using JavaScript and JSON, but I have encountered some issues along the way. My main struggle is figuring out how to extract specific content from a JSON file. After doing some research, I came across this code sn ...