Is there a way to consolidate two interface types while combining the overlapping properties into a union type?

Is there a way to create a type alias, Combine<A, B>, that can merge properties of any two interfaces, A and B, by combining their property types using union?

Let's consider the following two interfaces as an example:

interface Interface1 {
  type: string;
  another: bool;
}
interface Interface2 {
  type: number;
}

If we were to use

Combine<Interface1, Interface2>
, the resulting type should look like this:

type Result = {
  type: string | number;
  another: bool;
}

Answer №1

Begin by extracting all keys present in set A but not in set B, along with keys from set B that are not found in set A. For overlapping keys, define the union explicitly:

type Combine<A, B> = 
    Omit<A, keyof B> // elements in A not in B
  & Omit<B, keyof A> // elements in B not in A
  & { [K in keyof A & keyof B]: A[K] | B[K] }; // combination of both.

It is worth noting that specifying that certain keys may be absent in one set or the other can be achieved using Partial with the Omit:

type Combine<A, B> = 
    Partial<Omit<A, keyof B>> // potentially elements in A not in B
  & Partial<Omit<B, keyof A>> // possibly elements in B not in A
  & { [K in keyof A & keyof B]: A[K] | B[K] }; // combination of both.

Update: Upon Aaronium's inquiry about utilizing unions, an improved approach has been devised, where T extends any ? X : never is leveraged to expand all keys existing in any element within a union and then consolidate a union of corresponding values across interfaces. This results in a streamlined method:

// retrieves all viable keys from all interfaces within a union.
type AllKeysOf<T> = T extends any ? keyof T : never
// essentially performs T[K], but for unionized T it only yields T[K] for valid key members within the union.
type Get<T, K extends keyof any, Fallback=never> = T extends Record<K, any> ? T[K] : Fallback
// combines a union of interfaces, merging common keys into a union of possibilities.
type Combine<T> = {[K in AllKeysOf<T>]: Get<T,K>}

type TEST = Combine<{a:1} | {a:2, b:10} | {b: 11}>
// TEST = {a: 1|2, b: 10|11}

Keep in mind that adjusting the generic Fallback in Get</code to <code>never will exclude union elements lacking that key. Alternatively, setting it to undefined suggests that keys defined in some interfaces but not all might result in undefined values, resembling optionality. The exact interpretation of these different handling methods largely relies on your specific scenario, so experimentation with both never and undefined is recommended to determine desired behavior.

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

Achieving VS Code/typescript autocomplete functionality without the need to import the library

When a module (for example, moment.js, knockout, or big.js) is added with a <script> tag like this: <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.js"> </script> that defines a global property (for instance ...

One potential solution for fixing the error in GetRepository of TypeORM is to check for undefined properties before attempting to access them. This error typically occurs when trying to read properties of an undefined

[Nest] 171 - 08/31/2022, 8:35:42 PM ERROR [ExceptionHandler] Cannot read properties of undefined (reading 'getRepository') tenant-node | TypeError: Cannot read properties of undefined (reading 'getRepository') tenant-node | at Instance ...

Instructions on how to post an array by its ID when the value changes in the form, correspond with the ID

Whenever I change the value in the radio button within a form popup, I want to trigger this action. Below is the corresponding HTML code: <ng-container cdkColumnDef="injected"> <mat-header-cell *cdkHeaderCellD ...

Difficulty retrieving information using AngularJS service post selection of item

Currently, I am working on a project involving an AngularJS application. While using the service testPanelService, I encountered a problem where selecting an item from a list correctly logs the details of the selected item. However, when attempting to fetc ...

Obtaining attributes of a class from an object passed into the constructor

Consider the following code snippet: interface MyInterface { readonly valA: number; readonly valB: number; } class MyClass { readonly valA: number; readonly valB: number; constructor(props: MyInterface) { this.valA = props.val ...

Why does the ReactJS MaterialUI Modal fail to update properly?

Recently, I encountered a curious issue with my Modal component: https://i.stack.imgur.com/dkj4Q.png When I open the dropdown and select a field, it updates the state of the Object but fails to render it in the UI. Strangely, if I perform the same action ...

No members were exported by the module, please export an interface

I encountered this error: "/Users/robot/code/slg-fe/src/app/leaderboards/leaderboards.component.ts (2,10): Module '"/Users/robot/code/slg-fe/src/app/leaderboards/leaderboard"' has no exported member 'Leaderboard'. This is what my le ...

Property does not exist when dispatching in React Redux within componentDidMount

Currently, I am navigating my way through my initial project using React + Redux and have hit a few roadblocks while attempting to dispatch a function in the componentDidMount section. I tried to emulate the Reddit API example project from the Redux docume ...

The React component fails to render when clicking on a Material-UI MenuItem

In my code, there is a simple mui Menu, where a MenuItem should trigger the rendering of another React component. The issue I am facing is that the Menu is being rendered in a separate file, which contains the definitions for the close and handleClick func ...

Best practices for transferring date objects between a frontend developed in JavaScript/TypeScript and a backend built in ASP.net Core 5

An exciting project I am working on involves a web application with a backend REST web API developed in ASP.net Core 5 and a frontend Angular application written in TypeScript. One of the APIs from the ASP.net backend returns an instance of a C# object de ...

An issue with the Pipe searchByType is resulting in an error stating that the property 'type' is not found on the type 'unknown'

I keep encountering a range of errors like roperty does not exist on type 'unknown' after running the command ionic build --prod --release src/app/pages/top-media/top-media.page.ts:18:16 18 templateUrl: './top-media.page.html', ...

Strategies for evaluating a Promise-returning imported function in Jest

I am currently facing an issue with a simple function that I need to write a test for in order to meet the coverage threshold. import { lambdaPromise } from '@helpers'; export const main = async event => lambdaPromise(event, findUsers); The ...

What is the best way to include a new attribute in a TypeScript internal object?

I am trying to include a property declaration in the window.history object, but I received a TypeScript error message This is my code: const historyInstance = createHashHistory(); // npm hoistory module window.history.historyInstance = historyInstance; / ...

Exploring the Node environment setup within Nest.js

Currently, I am in the midst of setting up a Nest.js project and seeking an efficient solution for defining the Node environment used by the ConfigService to load environment variables: import { Module } from '@nestjs/common'; import { ConfigSer ...

What is the best way to filter out specific data fields from console.log in JavaScript?

When working with Java, I often use lombok to exclude certain fields from being printed. For instance, the @ToString.Exclude annotation can be used to prevent printing the user token. import lombok.ToString; public class TokenResponse { @ToString.Excl ...

The element 'PROGRAM_ID' is not recognized within the 'import @metaplex-foundation/mpl-token-metadata' type

I am currently in the process of creating a token within the Solana network, but I've encountered a particular issue. I have successfully installed @metaplex-foundation/mpl-token-metadata and integrated it into my code; however, an error is persisting ...

Implementing tailwindcss styles in a typescript interface with reactjs

In my code, I have a file named types.ts that defines an interface called CustomCardProps. I pass this interface to the CustomCard component within the home.tsx file. Additionally, I have a folder named constant with an index.ts file where I store values o ...

Uploading multiple strings to an Amazon S3 bucket using Node.js by piping a string

Suppose I have a simple loop similar to the one shown below: for (const i=0; i<3; i++) { to(`This incrementer is ${i}`) } At the end of the loop, I expect my file to contain: This counter is 0 This counter is 1 This counter is 2 I at ...

The Angular service successfully provides a value, yet it fails to appear on the webpage

Currently, I am starting to dive into Angular from the ground up. One of my recent tasks involved creating a component called 'mylink' along with a corresponding service. In my attempt to retrieve a string value from the service using 'obse ...

Parent Class implementation for dynamic loading of components

I have been working on creating a new code for dynamic component loading using a parent-child relationship. The child component is set to override the parent and will be used for dynamically loading components. I found this useful link that guided me throu ...