Tips on accessing fields for union types that are passed to a function in TypeScript

I'm currently diving into the world of TypeScript, teaching myself by putting my newfound knowledge into practice.

Below is the code I'm working on, but I've hit a roadblock trying to access the fields of the type passed to the function.

Code :


interface Product1 {
    name: string;
    category: string;
}

interface Product2 {
    name: string;
    price: number;
}


type Product = Product1 | Product2;

function DisplayProductDetails(data: Product) {
    const keys : string[] = Object.keys(data);
    keys.forEach((key) => {
        console.log(data[key])
    })
}

const p2 = {
    name: "iPhone",
    price: 999
}

DisplayProductDetails(p2)

Error: The error is on this line - console.log(data[key])

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Product'. No index signature with a parameter of type 'string' was found on type 'Product'.

Answer №1

When attempting to utilize a string as a key for the OverView type, you may encounter issues since this type only supports 3 keys: name, family, storage. The compiler may raise concerns about the index access due to the versatile nature of the string. Even if you eliminate the explicit string[] from the keys type, the error persists because Object.keys does not provide generic support and consistently yields an array of string.

To address this, consider the following solutions:

  • Construct a typed version of Object.keys
  • Utilize as assertion to convert the keys' type to an array of keys from OverView

For this response, the second solution will be implemented:

function LogKeyValuePair(data: OverView) {
  const keys = Object.keys(data) as (keyof OverView)[];
  keys.forEach((key) => {
    console.log(data[key]); // no error
  });
}

It is important to note that, given the union nature of OverView, the resulting keys array will solely consist of name as it represents the common key within the unions.

Answer №2

One issue is that the key type (which is a string) lacks specificity when it comes to indexing data (in this case, OverView). To properly index the data, you would require keyof OverView. However, Object.keys() only gives back an array of generic string values. One potential solution would be to utilize a type assertion in this scenario.

interface Overview1 {
  name: string;
  family: string;
}

interface Overview2 {
  name: string;
  storage: string;
}

type OverView = Overview1 | Overview2;

function LogKeyValuePair(data: OverView) {
  const keys = Object.keys(data) as (keyof OverView)[];
  keys.forEach((key) => {
    console.log(data[key]);
  });
}

const o2 = {
  name: "john",
  storage: "10 gb",
};

LogKeyValuePair(o2);

TypeScript Playground

Answer №3

An issue has occurred: the error is on this line console.log(data[key]) Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'OverView'. No index signature with a parameter of type 'string' was found on type 'OverView'.

Due to the fact that keys are defined as type string[], TypeScript is unable to determine if the key belongs to the Overview type. Here are some potential solutions to resolve this error.

Specify the type using the as keyword

By including this code

console.log(data[key as keyof OverView])
, TypeScript will recognize that the key is within the Overview type.

Note! While this solution may work, it can result in runtime errors. It is advisable to verify null values before accessing properties in the data object.

interface Overview1 {
    name: string;
    family: string;
}

interface Overview2 {
    name: string;
    storage: string;
}


type OverView = Overview1 | Overview2;

function LogKeyValuePair(data: OverView) {
    const keys : string[] = Object.keys(data);
    keys.forEach((key) => {
      console.log(data[key as keyof OverView])
    })
}

const o2 = {
    name: "john",
    storage: "10 gb"
}

LogKeyValuePair(o2)

Alternatively, specify the type when assigning the array of keys

function LogKeyValuePair(data: OverView) {
    const keys = Object.keys(data) as (keyof OverView)[];
    keys.forEach((key) => {
      console.log(data[key])
    })
}

Playground link

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

"Exploring the World of Websockets Using Ionic 3 and Angular

How can I successfully implement a Websocket in Ionic 3 and Angular 4? I attempted to use the socket.io-client package, but when I try to connect the websocket using the following code: this.socket = io(this.urls.websocket, {transports: ['websocket& ...

Tips for preventing repetition of code in multiple entry points in Rollup

My goal is to use rollup to process a group of input files and generate multiple output files in the dist directory that all have some common code shared between them. Below is my current rollup configuration: import path from 'path'; import pat ...

Arranging the output of a Typescript project

I'm currently advocating for Typescript to be implemented in our web application. Can anyone provide insight on the best method for structuring Javascript output files? Should they be excluded from source control? And when it comes to testing, is it p ...

Issue: Module '/Users/MYNAME/Desktop/Projects/MYPROJECTNAME' not found

I am currently in the process of compiling Node using TypeScript, and I'm still getting acquainted with it. An issue I encountered was that my /src files were not being updated when I made changes and restarted the server. To troubleshoot, I decided ...

Enhance Material UI with custom properties

Is it possible to add custom props to a Material UI component? I am looking to include additional props beyond what is provided by the API for a specific component. For example, when using Link: https://material-ui.com/api/link/ According to the document ...

Combining rxjs events with Nestjs Saga CQRS

I am currently utilizing cqrs with nestjs Within my setup, I have a saga that essentially consists of rxjs implementations @Saga() updateEvent = (events$: Observable<any>): Observable<ICommand> => { return events$.pipe( ofType(Upd ...

The Next.js app's API router has the ability to parse the incoming request body for post requests, however, it does not have the

In the process of developing an API using the next.js app router, I encountered an issue. Specifically, I was successful in parsing the data with const res = await request.json() when the HTTP request type was set to post. However, I am facing difficulties ...

Tips for modifying the language of an Angular Application's OneTrust Cookie Banner

I'm currently developing an Angular application and utilizing OneTrust for managing cookie consent. The issue I'm encountering is that while the rest of the components on the login page are properly translated into the target language, the OneTru ...

Failed to decipher an ID token from firebase

I'm feeling extremely frustrated and in need of assistance. My goal is to authenticate a user using Google authentication so they can log in or sign up. Everything worked perfectly during development on localhost, but once I hosted my app, it stopped ...

Every day, I challenge myself to build my skills in react by completing various tasks. Currently, I am facing a particular task that has me stumped. Is there anyone out there who could offer

Objective:- Input: Ask user to enter a number On change: Calculate the square of the number entered by the user Display each calculation as a list in the Document Object Model (DOM) in real-time If Backspace is pressed: Delete the last calculated resul ...

What is the process for implementing custom color props with Material-UI v5 in a React TypeScript project?

Looking to enhance the MUI Button component by adding custom color props values? I tried following a guide at , but encountered errors when trying to implement it in a custom component. The custom properties created in createPalette.d.ts did not work as ex ...

Angular provides a variety of functionality to control the behavior of elements in your application, including the

I have a page with Play, Pause, Resume, and Stop icons. When I click on the Play icon, the Pause and Stop icons are displayed. Similarly, I would like to show the Resume and Stop icons when I click on the Pause icon. I need help with this code. Thank you. ...

Is it possible to create a class object with properties directly from the constructor, without needing to cast a custom constructor signature

class __Constants__ { [key: string]: string; constructor(values: string[]) { values.forEach((key) => { this[key] = key; }); } } const Constants = __Constants__ as { new <T extends readonly string[]>(values: T): { [k in T[num ...

MSBUILD encounters numerous JQuery errors when compiling a web project with TypeScript

Currently, I am working on a .net core 3.1 (netcoreapp3.1) razor pages project that includes typescript files and a few javascript files. The project builds perfectly from Visual Studio 2019 (professional) as well as from the command line using MSBuild. H ...

Eliminate duplicate dropdown options in Angular 2 using a filter function

Is there a way to filter reporting results in an Angular 2 dropdown list? I am currently attempting to do so within the *ngFor template but haven't had any success. I will also try using a custom pipe. The data is coming from a JSON array. Specificall ...

Using TypeScript generics with the `keyof` operator may result in rejection

I created a custom method using the RXJS library which looks like this : function Subject<T>(t: T):T { return t; } In addition, I defined an interface that specifies the structure of my application values. Additional keys can be added to this i ...

List the attributes that have different values

One of the functions I currently have incorporates lodash to compare two objects and determine if they are identical. private checkForChanges(): boolean { if (_.isEqual(this.definitionDetails, this.originalDetails) === true) { return false; ...

Angular 5 - capturing form inputs - activating event upon selecting suggested values

When I click on suggested values below the input field, the (click)="doSomething()" event doesn't fire. How do I handle this issue? I would like to be able to type something in the input field and then have an event triggered when clicking on the su ...

How come the hasOwnProperty function does not remove objects of type {}?

I am working with a complex type called ReactNode from the version @types/react 16.9.17 and TypeScript v3.7.4. import React, { ReactNode } from 'react'; My goal is to reduce this type to a new type that includes the property children. To achie ...

Ways to determine the types of props received by a function when the arguments vary for each scenario?

I have a specialized component that handles the majority of tasks for a specific operation. This component needs to invoke the onSubmit function received through props, depending on the type of the calling component. Below is an example code snippet show ...