Why does typescript allow the invocation of functions with an incorrect interface type?

Let's look at the scenario presented below. Notice that when func is called with an argument of type One, Typescript does not report any errors - what could be the reason behind this?

export interface One {
    common?: string
    one?: string;
}

export interface Two {
    common?: string
    two?: string;
}


export function func(arg: Two) {
    // do something!
}


const one: One = {
    common: 'common',
    one: 'One'
};

const two: Two = {
    common: 'common',
    two: 'Two'
}

func(one);

Answer №1

The root problem lies in the fact that One and Two have been defined as mutually compatible types.

Although there may not be a definitive source of documentation for this particular issue, referencing the (slightly outdated) TypeScript specification reveals that if all properties of a target object type T align with those of a source type S, then a value of type S can be assigned to a variable of type T.

In this scenario, One is assignably equivalent to Two due to:

  • Two's optional property common is a string, just like One's;
  • Two's optional property two is a string, while One lacks a property by that name.

Conversely, Two can be assigned to One for similar reasons:

  • One's optional property common matches Two's;
  • One's optional property one corresponds to Two's, although Two does not possess a property named this way.

This compatibility might appear unexpected. However, TypeScript 2.4 introduced weak type detection that mandates at least one common property between all-optional-property types like One and Two. Yet, since both include the common property, weak type checking is disabled.


To differentiate between two inadvertently compatible types, consider adding problematic property keys explicitly to the opposite types as optional properties of type never or undefined:

export interface One {
  common?: string
  one?: string;
  two?: undefined;
}

export interface Two {
  common?: string
  one?: undefined;
  two?: string;
}

This adjustment doesn't alter the intended assignments to these types:

const one: One = {
  common: 'common',
  one: 'One'
}; // remains valid

const two: Two = {
  common: 'common',
  two: 'Two'
} // still acceptable

However, now the compiler treats One and Two as separate entities:

func(one); // generates an error!
//   ~~~ <--  Properties' types are incompatible.

Hopefully, this advice proves beneficial. Best of luck!

Link to Playground for Code Testing

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

When attempting to publish an index.d.ts file using npm, the module is

We are currently in the process of developing an npm package that will serve as the foundation for most of our projects. However, we have encountered some issues that need to be addressed: The index.d.ts file of our base npm package is structured as shown ...

What is the best way to access an optional field in Typescript without causing errors?

Is there a way to dereference an optional field from an interface in the following scenario? interface Sample { key1?: Array<Obj1> } interface Obj1 { a?: Obj2; } interface Obj2 { b?: string; } const a: Sample["key1"][number][" ...

The type 'Context' is lacking the Provider and Consumer properties from the type 'Context<unknown>'. TS2345 error occurred

I am attempting to utilize rootstore to access two separate stores within my react Project. RoorStore.ts => import ExtractionStore from "./extractionStore"; import UserStore from "./userStore"; import { createContext } from "vm"; export class RootSt ...

Creating TypeScript projects without the use of a conventional IDE or text editor

Due to restrictions in my workplace, I am unable to download or install any applications, regardless of my job duties. I am interested in migrating several web apps to Angular 2 using TypeScript. I am a C# developer in my free time and I find TypeScript ap ...

Dealing with TSLint errors within the node_modules directory in Angular 2

After installing the angular2-material-datepicker via NPM, it is now in my project's node_modules folder. However, I am encountering tslint errors that should not be happening. ERROR in ./~/angular2-material-datepicker/index.ts [1, 15]: ' should ...

Issue with TypeScript in VSCode: "Unable to save file 'x' as it would overwrite the input file."

As I work on improving my JavaScript quality with TypeScript in VSCode, I’m encountering an issue with my tsconfig.json file. It keeps throwing errors when trying to write my .js files, specifically displaying the message: "Cannot write file 'lib/c ...

Utilizing WebPack 5 in conjunction with Web workers in a React/Typescript environment

Can someone help me figure out how to make a web worker function properly with create-react-app, Typescript, and Webpack 5? I've been struggling with limited documentation and can't seem to find a clear explanation. I'm trying to avoid using ...

Is there any available tool that can autoformat TypeScript in Sublime Text?

I've been utilizing SublimeText for my TypeScript projects, and up until now, I've relied on JsFormat for automatic formatting. Unfortunately, JsFormat doesn't support TypeScript. Are there any alternative tools I can use for auto formatting ...

Creating an interactive questionnaire

Looking for insights on the following situation: I'm working with a survey structure that consists of questions and answers: questions: Question[]; answer: Answer[]; Where Question is defined as: export class Question { idQuestion: string; ...

The function you are trying to call is not callable. The type 'Promise<void>' does not have any call signatures. This issue is related to Mongodb and Nodejs

Currently, I am attempting to establish a connection between MongoDB and Node (ts). However, during the connection process, I encountered an error stating: "This expression is not callable. Type 'Promise<void>' has no call signatures" da ...

My React project is unable to locate a file after I modified its extension from .js to .tsx

After using npx create-react-app my-app to start my React project and adding Typescript, I encountered an issue after converting one of my components to a .tsx file. The error message I received was: Module not found: Error: Can't resolve './cont ...

Tips for maintaining the selection when switching pages with smart-table?

I have implemented smart-table in my project to allow users to select records from different pages and view them in a preview section. However, I am facing an issue where the selection made on the first page does not persist when navigating back to it aft ...

Implementing a 12-month display using material-ui components

Just starting out with ReactJs, TypeScript, and material-ui. Looking to display something similar to this design: https://i.stack.imgur.com/zIgUH.png Wondering if it's achievable with material-ui. If not, any suggestions for alternatives? Appreciate ...

Angular 2 - Dependency Injection failing to function

I have created two different implementations for an interface and assigned them as providers for two separate components. However, I am encountering the following error: Error: Can't resolve all parameters for ChildComponent: (?). What could be the i ...

It appears that I am encountering an issue when attempting to utilize the async pipe operator

<div class="image" *ngFor="let entry of (currentUserData | async)?.entries"></div> Error message: The term 'currentUserData' is not recognized. Please check the component declaration, template variable declarations, and element refe ...

How can I suggest the return type of a function that is out of my control?

When I attempt to parse a JSON-formatted string, a linter error is triggered: let mqttMessage = JSON.parse(message.toString()) // ESLint: Unsafe assignment of an `any` value. (@typescript-eslint/no-unsafe-assignment) Given that I am in control of the con ...

Issue with Select Box Value not updating in HTML Document Object Model

The issue I'm facing is that the select box DOM value does not update after the value has been changed in the component.ts file. Could you please review the code provided below: <form class="form-horizontal aformgroups" [formGroup]="Purchase ...

Solving the issue of loading Ember Initializers during the transition to TypeScript

While following the ember quick start tutorial, I attempted to switch from Javascript to Typescript. Converting the .js files to .ts files resulted in an error with the ember-load-initializers import. The application is unable to run until this issue is re ...

Retrieving latitude and longitude from place id in an Angular Google Maps component

Currently utilizing the google-maps component to extract latitude and longitude from Google Maps prediction data. Additionally, I have integrated a search bar using google-maps component. I have successfully implemented a search bar with ngx-google-places ...

What is the importance of having a generic Locals type Request in express?

As I was working on creating the properties of a Request object without using global declarations, I encountered a problem that threw me off course. I attempted to utilize the generic Locals for Request in order to set up the req.auth property, but unfort ...