How to avoid property name conflicts when extending interfaces in Typescript

Is it possible to achieve something like this using TypeScript, such as renaming a property?

interface Person {
    name: string
    age: number
}

interface Pet {
    age: string
}

interface Zoo extends Pet, Person {}

How can we prevent this error from occurring:

Interface 'Zoo' cannot simultaneously extend types 'Person' and 'Pet' Named property 'age' of types 'Person' and 'Pet' are not identical.ts(2320)

[UPDATE]

I'm seeking a solution that yields the following desired output:

interface Zoo {
    name: string
    age: number
}

Answer №1

Oh, so your goal is not to change property names; you just want to eliminate any conflicting properties from one of the interfaces.

This concept closely resembles the notion of an object spread type operator, which TypeScript currently lacks as a part of its language at the type level. Currently, when it comes to generic spreads, the type system treats them as an intersection, which is only accurate for non-conflicting properties. However, at the value/expression level, TypeScript effectively manages spreads of concrete types. As such, you can achieve the specific Zoo you desire by convincing the type system that you possess a value of type Pet, another value of type Person, and a value formed by spreading them:

interface Person {
  name: string
  age: number
}

interface Pet {
  age: string
  trained: boolean // I added this because otherwise Zoo=Person which is weird
}

declare const person: Person; // pretend we have a person
declare const pet: Pet; // pretend we have a pet
const zoo = { ...pet, ...person }; // spread them into a new variable
type ZooType = typeof zoo; // acquire the type of that variable

interface Zoo extends ZooType { }; // convert it into an interface just because

If you're hesitant about dealing with values (especially if you don't have any readily available) and wish to carry out this process purely at the type level, you can craft a spread-like type operator yourself using mapped and conditional types. A recommended implementation was suggested by one of the language designers for Merge<L,R>, which works sufficiently well with certain considerations regarding optional/readonly/etc properties.

In your scenario, where there are no optional or readonly properties involved, here is a simpler version known as Merge<L, R>:

type Merge<L, R> = R & Pick<L, Exclude<keyof L, keyof R>>;

You'll notice that it mirrors the functionality of the aforementioned value-level spread:

interface Zoo extends Merge<Pet, Person> { };

declare const zoo: Zoo;
zoo.name; // string
zoo.age; // number
zoo.trained; // boolean

Please bear in mind that if age were optional in Person, then Merge<Pet, Person> would make age optional in Zoo. This outcome may align with your intentions, but a spread wouldn't exhibit the same behavior; {...pet, ...person} would always include an age since it is mandatory in Pet. Consequently, Zoo["age"] might be something like string | number, which the previously shared Spread<L, R> operator could manage more accurately. Furthermore, neither Merge<> nor the linked Spread<> guarantee flawless handling of readonly properties, especially given the ambiguity surrounding the appropriate treatment of such properties.

Well, I hope this information proves helpful! Best of luck!

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

Stop the MatSort feature from activating when the space key is pressed in Angular Material

I am currently using angular material tables and have implemented filters for each column. The filter inputs are located in the row header of each column, which is working fine. However, I am facing an issue where whenever I type and press the space key, ...

What is the best way to retry an action stream observable in Angular/RxJS after it fails?

Kindly disregard the variable names and formatting alterations I've made. I've been attempting to incorporate RxJS error handling for an observable that triggers an action (user click) and then sends the request object from our form to execute a ...

Autocomplete feature in Angular not showing search results

I am currently using ng-prime's <p-autocomplete> to display values by searching in the back-end. Below is the HTML code I have implemented: <p-autoComplete [(ngModel)]="agent" [suggestions]="filteredAgents" name="agents" (completeMethod)="f ...

Querying Cloud Firestore with User ID

I'm facing an issue with retrieving a subset of data based on the first letter of the name and including the UID of the document. No matter what I try, it just returns empty data. fetchDataByFirstLetter(firstLetter: string) { this.afs.collection(&a ...

Don't initialize each variable within the constructor of a class, find a more efficient approach

I have a collection of JavaScript classes representing different models for my database. Each model contains attributes such as name, email, and password. Is there a more efficient way to create a new User instance without manually assigning values to ea ...

Exploring Nested JSON Iteration in Angular4

I am struggling to iterate through a nested JSON and extract the desired output. Can someone assist me in retrieving the bpmn:startEvent id value from the JSON provided below? { "bpmn:definitions":{ "@attributes":{ "xmlns:xsi":"h ...

What steps do I need to follow to write this function in TypeScript?

I am encountering a problem when building the project where it shows errors in 2 functions. Can someone please assist me? The first error message is as follows: Argument of type 'IFilmCard[] | undefined' is not assignable to parameter of type &a ...

Learning how to merge two observable streams in Angular2 by utilizing RxJS and the powerful .flatMap method

Within my Angular2 app, I have created an Observable in a Service called ContentService. Here is a simplified version of the code: @Injectable() export class ContentService { constructor(private http:Http, private apiService:ApiService) { th ...

Utilizing the functionalities provided by node.js, I came across an issue and sought out a solution for the error message "TypeError: __WEBPACK_IMPORTED_MODULE_3_fs__.writeFile is not a function"

I have created a project centered around {typescript, react, electron, gaea-editor}. During an event, I utilized fs.writeFile() but encountered an error. The specific error message was: TypeError: __WEBPACK_IMPORTED_MODULE_3_fs__.writeFile is not a functi ...

What is the best way to modify a particular internal route parameter within Angular 2?

In the midst of creating a versatile calendar that can showcase various types of data, I have devised a unique URL structure to guide me: todo/2017/01/01 showcases daily todos birthdays/2017/01/01 displays birthdays for that particular day todo/2017/01 g ...

Introduce a specialized hierarchical data structure known as a nested Record type, which progressively ref

In my system, the permissions are defined as an array of strings: const stringVals = [ 'create:user', 'update:user', 'delete:user', 'create:document', 'update:document', 'delete:document&ap ...

Using the index in Vue.js to locate a method within an HTML file

Currently, I am attempting to make use of the reference "index" located within <tr v-for="(note, index) in noteList" v-bind:key="index" in order to call shareToPublic(index). The method selectedID() allows for the selection of the ...

Obtain a segment of the string pathway

In this scenario, there is a file path provided below. Unlike the rest of the URL, the last part (referred to as video2.mp4) regularly changes. The language used for this project is either Javascript or Typescript. file:///data/user/0/com.sleep.app/files/ ...

Displaying Typescript command line options during the build process in Visual Studio

As I delve into the world of VS 2015 Typescript projects, I find myself faced with a myriad of build options. Many times, the questions and answers on Stack Overflow mention command line options that I'm not completely familiar with, especially when i ...

What are the steps to effectively utilize an interface within a TypeScript file that contains its own internal import?

Currently, I am in the process of developing a React JavaScript project using WebStorm and attempting to enable type hinting for our IDEs (including VS Code) by utilizing TypeScript interfaces and JSDoc annotations. Our goal is to potentially transition to ...

Compilation failure due to Typescript initialization issue

Encountering a TypeScript error in my IntelliJ-Idea 2017.1.1 IDE I have enabled JavaScript, NodeJS, and TypeScript Compiler. I have exhausted all solutions but the issue persists, perhaps I am missing something. Error: Initialization error (typescript ...

Angular 12's BehaviorSubject should have been empty object array, but it unexpectedly returns undefined

Exploring different scenarios with a livesearch functionality: No user input (observable = undefined) No results found (observable = empty array) Results found (observable = non-empty array) The issue lies in how my behavior subject interprets an empty a ...

Steps for showing a component (popup modal) just one time with React hooks

Is there a way to implement a popup modal that only appears once using hooks and localStorage? The modal should already appear upon page load. const [showModal, setShowModal] = useState<boolean>(true) return( <ModalIsContractor ...

Warning: The TypeScript version in use may not support all features. The current language level is set to XX in Visual Studio 2019

After installing VS 2019, I noticed that Microsoft.TypeScript.MSBuild 4.2.3 was added. On my Windows 10 OS, I also installed it using NPM in the following way: However, upon opening VS 2019, I encountered the warning below: TypeScript 3.4 feature Curre ...

Invoking a controller from another controller in the Express framework using Typescript

Currently, I am trying to call a controller from another controller in my code. While attempting to pass parameters using {params: {task_id: String(task_id), result}}, TypeScript is flagging an error indicating that res does not have all the required attri ...