Exploring Objects with Union Types in TypeScript

Looking to iterate through an object that combines two interfaces.

    interface Family {
      cat: string;
      age: string;
      family: string;
      lastYearFamily: string;
    }
    
    interface Model {
      cat: string;
      age: string;
      model: string;
      lastYearModel: string;
    }
    
    interface Props {
        attributionType: 'family' | 'model';
        attributions?: Family[] | Model[];
    }
    
    const RowComponent = ({
    attributionType,
    attributions
    }: props) =>{
    
       return (
          {attributions && attributions.map((attribution: Family | Model ) => (
                             <tr>
                                {
                                    attributionType === 'family' && (
                                        <React.Fragment>
                                            <th>{attribution.family}</th>
                                            <th>Family</th>
                                        </React.Fragment>
                                    )
                                } 
                                {
                                    attributionType === 'model' && (
                                        <React.Fragment>
                                            <th>{attribution.model}</th>
                                            <th>Model</th>
                                        </React.Fragment>
                                    )
                                } 
                             </tr>
                        ))}
    );
    
    }

Struggling with accessing non-common members in the union object.

Can only access cat and age, not family, lastYearFamily, etc.

Prefer to keep code generic without separate components for each attribution type.

Answer №1

When defining the string 'family' in the Props interface, it is important to explicitly specify that it should infer to Family[] for the attributions. Otherwise, there may be confusion regarding the correlation between attributionType and attributions.

    // your code
    interface Props {
        attributionType: 'family' | 'model';
        attributions?: Family[] | Model[];
    }

To provide clear guidance to the compiler, it is recommended to define separate interfaces for each type and then combine them accordingly:

interface FamilyProp {
  attributionType: "family";
  attributions?: Family[];
}

interface ModelProp {
  attributionType: "model";
  attributions?: Model[];
}

type Props = ModelProp | FamilyProp;

function foo(bar: Props) {
    if (bar.attributionType === "model") {
        bar.attributions[0].lastYearModel; // compiles fine
    }
    if (bar.attributionType === "family") {
        bar.attributions[0].lastYearFamily; // compiles fine
    }
}

By using Type Guard, the compiler will properly infer the types within the if statements.

Answer №2

To implement this functionality, one would typically utilize custom type guards. These guards involve converting a variable to a potential type and verifying the presence of a specific field unique to that type. This process allows for the inference that the value stored in the variable is indeed of the specified type.

interface Family {
      cat: string;
      age: string;
      family: string;
      lastYearFamily: string;
}
    
interface Model {
      cat: string;
      age: string;
      model: string;
      lastYearModel: string;
}

const isFamily = (f: Family|Model): f is Family => {
    return (f as Family).family !== undefined
}

const isModel = (f: Family|Model): f is Model => {
    return (f as Model).model !== undefined
}

const x : (Family | Model)[] = [
    {cat: "x", age: "y", family: "z", lastYearFamily: "w"},
    {cat: "x", age: "y", model: "z", lastYearModel: "w"}
]

x.map(e => {
    if (isFamily(e)) {
        return e.family;
    } else {
        return e.model;
    }
})

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 'Component' binding element is assumed to have an unspecified 'any' type in TypeScript

Hello, I'm new to coding and encountering an issue with the code below. My goal is to create a protected "Dashboard" page, but I keep getting a binding error that says: Binding element 'Component' implicitly has an 'any' type.ts( ...

Tailored production method based on specific criteria

One of my challenges is to create a versatile factory method using typescript. The main objective is to initialize a class based on its name using generics, instead of employing if/else or switch statements. I am aiming for similar functionality as this ...

Modify the key within an array of objects that share a common key

I have an object structured as follows: NewObjName: Object { OLDCOLUMNNAME1: "NEWCOLUMN_NAME1", OLDCOLUMNNAME2: "NEWCOLUMN_NAME2", OLDCOLUMNNAME3: "NEWCOLUMN_NAME3"} Next, there is an array containing objects in this format: ...

What is the reason behind typescript making it necessary for me to find a way to set a value of type

function f1() { const v : string = String(); if(v) {alert("IF");} // OK const b : boolean = v; // Type 'string' is not assignable to type 'boolean'. if(b) {alert("BOOLEAN");} } f1(); My approach to this issue involv ...

How can I utilize the Redux store outside of a component in a React application with ASP.NET Core and TypeScript?

While I have some experience with React, I am new to using Redux. Luckily, Visual Studio 2017 comes with a built-in template for React + Redux under .NET Core 2.0. About my environment: Visual Studio 2017 React 15.6.1 TypeScript 2.4.1 Redux 3.7.1 Rea ...

Tips for utilizing the keyword 'this' within a Promise

Seeking assistance with resolving an issue involving an undefined error when attempting to make an http request within a Promise function. The error occurs due to this.http.post being undefined, indicating that there is an issue with accessing this properl ...

The routerlink feature consistently directs back to the default page

I am facing an issue where my routerlink does not redirect me to the correct path in app.routes.ts when clicked. Even though the routerlinks are set as 'user/teams' and 'user/dashboard' respectively. I can access the pages by directly ...

retrieve a nested object's property using a dynamic string

Here is the object model I am working with: export class FrcCapacity { constructor( public id?: number, public frcId?: number, public capGroupId?: number, public capGroup?: CapGroup, public salesProductId?: number, public p1?: num ...

The element of type 'OverridableComponent<LinkTypeMap<{}, "a">>' cannot be assigned to a 'ReactNode'

I'm currently working on a project where there's a component named ListItemTextStyle. Within that component, the prop type is defined as follows: import { LinkProps, ListItemButtonProps, } from '@mui/material'; type IProps = LinkP ...

Adding Components Dynamically to Angular Parent Dashboard: A Step-by-Step Guide

I have a dynamic dashboard of cards that I created using the ng generate @angular/material:material-dashboard command. The cards in the dashboard are structured like this: <div class="grid-container"> <h1 class="mat-h1">Dashboard</h1> ...

Angular 2 decorators grant access to private class members

Take a look at this piece of code: export class Character { constructor(private id: number, private name: string) {} } @Component({ selector: 'my-app', template: '<h1>{{title}}</h1><h2>{{character.name}} detai ...

Is it possible to maintain component data in Angular while also incorporating dynamic components?

All the code you need can be found here: https://stackblitz.com/edit/angular-keep-alive-component?file=src/app/app.component.ts Is it possible to maintain the state of entered values when switching components? I am currently utilizing dynamic component r ...

Currently, I am utilizing version 6.10.0 of @mui/x-date-pickers. I am interested in learning how to customize the color and format of a specific component within the library

I'm currently using @mui/x-date-pickers version 6.10.0 and I need to customize the color and format for a specific section in the mobile view. How can I achieve this? I want to display the date as "May 31st" like shown in the image below. Is there a ...

Tips for addressing the browser global object in TypeScript when it is located within a separate namespace with the identical name

Currently diving into TypeScript and trying to figure out how to reference the global Math namespace within another namespace named Math. Here's a snippet of what I'm working with: namespace THREE { namespace Math { export function p ...

Is it possible to utilize useRef to transfer a reference of an element to a child component?

When I want to mount something into the element with id tgmlviewer, I call it a viewer object. This process works smoothly when there is only one component of this kind. import React, { useEffect } from "react"; import { Viewer } from "../.. ...

Defining a structure for an entity in which its attributes distinguish between different data types and an array combination

I strongly believe that the best way to showcase this concept is through a clear example: enum EventType { A, B, C }; type MyEvent = [EventType.A, number] | [EventType.B, string] | [EventType.C, number, string]; const eventsGrouped: Record<Event ...

TypeOrm is struggling to identify the entities based on the directory path provided

Currently, I am utilizing TypeORM with NestJS and PostgreSql to load entities via the datasource options object. This object is passed in the useFactory async function within the TypeORM module as shown below: @Module({ imports: [TypeOrmModule.forRootAsy ...

Webpack, TypeScript, and modules are set to "esnext," resulting in a change to undefined

In my setup, I am using webpack with typescript (via ts-loader). To enable code splitting in webpack, it is necessary to adjust the module setting to esnext in the tsconfig file: // tsconfig.json { "compilerOptions": { "module": ...

Working with Angular to add various items to an array based on multiple conditions

Currently, I am a beginner in TypeScript and currently involved in an Angular project. As part of my work, I need to make an API call and perform various operations on the received data: public data_Config: IConfig[] = []; this.getService.Data(input).sub ...

No matter what I attempt, Ng-options is still failing to work properly

This is my custom selection element: <select ng-options="country.country for country in countries" formControlName="country"></select></label> Below is the TypeScript component code associated with it: import { Component } from ' ...