Combining interfaces with union types will only recognize properties that are shared between the options

Is it possible to use two interfaces in TypeScript as in a Union Types? The example below shows that I am unable to check the type of the parameter and can only access properties shared by both interfaces. Any suggestions on what I should do in this situation?

https://i.sstatic.net/LzxAG.png

Answer №1

To handle the different types of data, you should utilize discriminated unions.

interface Cat {
   id: string;
   name: string;
   type: "Cat";
}

interface Dog {
   id: string;
   age: number;
   type: "Dog";
}

function animals(input: Cat | Dog) {
   if(input.type === "Dog") {
      input.age 
   }
}

Playground

Answer №2

input is defined with the type Foo | Bar, meaning that TypeScript recognizes it can be either of those types but requires further specification. The only common property between them is the id. It's essential to implement type checking in such cases. One way to approach this is by creating interfaces as shown below:

interface Foo{
  id: string;
  name: string;
  type: "Foo"
}

interface Bar{
  id: string;
  phoneNumber: string;
  type: "Bar"
}

function checkInput(input: Foo | Bar){
  if(input.type === "Bar"){
    input.phoneNumber
  } else {
    input.name
  }
}

In the example above, the type property is utilized for distinction. You can test this code snippet in the TypeScript Playground.

Answer №3

To enhance the functionality of your interface, start by inheriting from a simple interface with the id attribute:

interface IdAble {
  id: string;
}

interface Product extends IdAble {
  name: string;
}

interface User extends IdAble {
  phoneNumber: number;
}

Answer №4

To begin with, you must narrow down the type before assigning unique attributes that are not shared.
There are two options available depending on your specific situation:

  1. Incorporate a common attribute and assign distinct values to differentiate between them.
// First approach
interface Foo {
   id: string;
   name: string;
   type: "foo";
}

interface Bar {
   id: string;
   phoneNumber: number;
   type: "bar";
}

function baz(input: Foo | Bar) {
   if (input.type === "bar") {
      input.phoneNumber
   }
   if (input.type === "foo") {
      input.name
   }
}
  1. Determine if the key exists within the object.
// Second approach
interface Foo2 {
   id: string;
   name: string;
}

interface Bar2 {
   id: string;
   phoneNumber: number;
}

function baz2(input: Foo2 | Bar2) {
   if ('phoneNumber' in input) {
      input.phoneNumber // The type will be Bar2.
   }
   if ('name' in input) {
      input.name // The type will be Foo2.
   }
}

Playground

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

The invocation of `prisma.profile.findUnique()` is invalid due to inconsistent column data. An invalid character 'u' was found at index 0, resulting in a malformed ObjectID

The project I'm working on is built using Next.js with Prisma and MongoDB integration. Below is the content of my Prisma schema file: generator client { provider = "prisma-client-js" } datasource db { provider = "mongodb" url = env("DATABA ...

What is the purpose of exporting both a class and a namespace under the same name?

While exploring some code, I came across a situation where a class and a namespace with identical names were exported from a module. It seems like the person who wrote this code knew what they were doing, but it raised some questions for me. Could you shed ...

What is the best approach to perform type checking on a function that yields varying types depending on the values of its

Currently, I am facing a challenge with a function that takes an argument and returns a different type of value depending on the argument's value. For instance: function foo(arg: 'a' | 'b') { if (arg === 'a') { ret ...

Angular5 causing all divs to have click events at once instead of individually triggered

I am a beginner when it comes to working with Angular and I have encountered an issue. I created a click event on a FAQ page in Angular 5, but the problem is that when I click on one FAQ, they all open up instead of just the targeted one. Here is my TypeS ...

Custom Type Guard Leads to Intersection Type Outcome

Recently, I've been experimenting with Typescript and decided to explore the creation of an innovative Either type that could distinguish between success and failure scenarios. Utilizing a user-defined type guard, I managed to precisely narrow down th ...

The addition operator is not compatible with the given types

Hello, I am currently working on integrating PayPal into an Angular 5 project. The code snippet below shows how I render PayPal buttons using a function: ngAfterViewChecked(): void { if (!this.addScript) { this.addPaypalScript().then(() => { ...

What could be causing my webpack bundler to generate several main.js files?

After realizing that tree shaking was not working correctly due to compiling TypeScript to 'commonjs', I switched it to 'ES2015' and now my build output appears like this: click here for the image. Can anyone explain what is happening ...

Enhance the design of MDX in Next.js with a personalized layout

For my Next.js website, I aim to incorporate MDX and TypeScript-React pages. The goal is to have MDX pages automatically rendered with a default layout (such as applied styles, headers, footers) for ease of use by non-technical users when adding new pages. ...

In Typescript, is there a way to retrieve the name of an object when working with object types?

I am working on creating a for() loop to check the first field in my template with the status INVALID and I need to retrieve the name of this object. This is what I have tried so far: for(var mandatoryField in form.controls){ if(form.controls[mandato ...

What is the method for opening the image gallery in a Progressive Web App (PWA)?

I am struggling to figure out how to access the image gallery from a Progressive Web App (PWA). The PWA allows me to take pictures and upload them on a desktop, but when it comes to a mobile device, I can only access the camera to take photos. I have tried ...

The use of `super` in Typescript is not returning the expected value

Trying to retrieve the name from the extended class is causing an error: Property 'name' does not exist on type 'Employee'. class Person { #name:string; getName(){ return this.#name; } constructor(name:string){ ...

Are you looking to discontinue receiving updates from the @Output EventEmitter?

Explore the Angular website where you can find a demonstration of communication between Parent and Child components through @Output() onVoted = new EventEmitter<boolean>();. Check it out below. In this specific scenario, is it necessary to unsubscri ...

Unable to extract data from text-box after utilizing the Date picker

Hello Team at Stack Overflow, When I click the edit link to modify customer details, the edit form is displayed. The form shows all existing data except for the datepicker data which is not being displayed. All the data is coming from the Web API. EditUs ...

Issue encountered when trying to use Array.sort() method to sort an array of objects

I'm facing an issue sorting an array of objects by a name property present on each object. When utilizing the sort() method with the given code snippet, I encounter the following error: ERROR ReferenceError: b is not defined This is my code block: m ...

Exploring TypeScript: Navigating the static methods within a generic class

I am trying to work with an abstract class in TypeScript, which includes an enum and a method: export enum SingularPluralForm { SINGULAR, PLURAL }; export abstract class Dog { // ... } Now, I have created a subclass that extends the abstract cla ...

The issue arising from utilizing the export class function in Angular 8

Hey there! I'm working on an Angular application and just getting started with it. My current version is Angular 8, and I've encountered an issue that I need help with. In my project, I have a shared model named "Client" which is defined in a fi ...

Create an object with identical keys as another object

I need to create a mapping between two objects. The first object can have keys of any string type and values of a generic type. I want to map the second object with the same keys, allowing different types for the values (ideally extracted from the generi ...

Creating void functions in TypeScript

I encountered a section of code within a custom component that is proving to be quite puzzling for me to comprehend. public onTouch: () => void = () => {} The function onTouch is being assigned by the private method registerOnTouch(fn: any) { ...

I'm having trouble incorporating TypeScript into my React useState hooks. Can someone help me troubleshoot?

I've been encountering challenges when trying to integrate Typescript into my React code, especially with the useSate hooks. I've dedicated several days to researching how to resolve this issue, but I'm uncertain about what should be passed ...

:id Path replaces existing routes

My route configuration looks like this: const routes: Routes = [ { path: '', component: UserComponent, children: [ { path: '', component: LoginComponent }, { path: 'signup', component: SignupComponent } ]}, ...