Accessing a property in Typescript is limited to a specific union type

I am relatively new to Typescript, so please bear with me as I navigate through this challenge.

In a specific use-case scenario I have created an array that can contain instances of both "Class One" and "Class Two". My goal is to iterate through this array using a forEach loop and perform actions when the property 'drawer' is present.

However, I encounter an issue in Typescript while trying to access 'drawer' within the forEach loop:

Property 'drawer' does not exist on type 'One | Two'.
  Property 'drawer' does not exist on type 'Two'.

Even though 'drawer' is clearly present in 'One'.

If I set 'arrayWithBothOneAndTwo' to

let arrayWithBothOneAndTwo = [] as One[]
, it resolves the error, but I know this isn't the best solution since the array can also contain instances of 'Two', leading to possible errors.

If I modify the forEach loop like this:

    arrayWithBothOneAndTwo.forEach((item: One) => {
      console.log(item.drawer)
    })

This results in another error:

Argument of type '(item: One) => void' is not assignable to parameter of type '(value: One | Two, index: number, array: (One | Two)[]) => void'.
  Types of parameters 'item' and 'value' are incompatible.
    Type 'One | Two' is not assignable to type 'One'.
      Property 'drawer' is missing in type 'Two' but required in type 'One'.

To summarize:

I need a way to access 'item.drawer' within my forEach loop without causing any errors in my code. Any suggestions or solutions would be greatly appreciated!

    class One {
      drawer: string[] = []

      constructor () {
        this.drawer.push('A')
        this.drawer.push('B')
        this.drawer.push('C')
      }
    }

    class Two {
      notADrawer: string[] = []

      constructor () {
        this.notADrawer.push('D')
        this.notADrawer.push('E')
        this.notADrawer.push('F')
      }
    }

    // Create arrays with instances of One and Two classes
    const someOnes = [new One(), new One()]
    const someTwos = [new Two(), new Two(), new Two(), new Two()]

    // Initialize an array that can hold instances of One or Two 
    let arrayWithBothOneAndTwo: Array<One | Two> = []

    // Populate the array with instances of One and Two classes
    arrayWithBothOneAndTwo = [...someOnes, ...someTwos]
    
    // Iterate through the array and display the 'drawer' array if present
    arrayWithBothOneAndTwo.forEach((item) => {
      console.log(item.drawer)
    })

Answer №1

In order to properly narrow the type in TypeScript, you need to include a check to determine if the property exists:

arrayWithBothOneAndTwo.forEach((item) => {
    if('drawer' in item) {
        console.log(item.drawer); // item type now narrowed to One
    }
});

If desired, you can be more clear by using a type predicate in a user-defined type guard:

arrayWithBothOneAndTwo.forEach((item) => {
    if(isOne(item)) {
        console.log(item.drawer);
    }
});

function isOne(item: One | Two): item is One {
  return 'drawer' in item;
}

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

Error message in the console when using a single select checkbox in PrimeNG

When I select one checkbox, the others should be automatically unselected. Additionally, clicking on a selected checkbox should also deselect it. Currently, my implementation looks like this: In the HTML page, I am utilizing *ngFor in the following manner ...

Develop a TypeScript class that includes only a single calculated attribute

Is it advisable to create a class solely for one computed property as a key in order to manage the JSON response? I am faced with an issue where I need to create a blog post. There are 3 variations to choose from: A) Blog Post EN B) Blog Post GER C) Bl ...

Even in report-only mode, Content Security Policy effectively blocks the execution of inline scripts

Currently, I have implemented a Content Security Policy (CSP) in 'Content-Security-Policy-Report-Only' mode with a specified report-uri. There is an inline JavaScript code running on the page that the CSP restricts. My initial expectation was tha ...

Ways to incorporate React.js into HTML for showcasing a portfolio

Having difficulties rendering my code using React.js for my portfolio. I am attempting to showcase my projects with images and p tags containing project titles and my role. Additionally, I would like the React elements to be clickable, directing users to t ...

Are there any alternatives to ui-ace specifically designed for Angular 2?

I am currently working on an Angular2 project and I'm looking to display my JSON data in an editor. Previously, while working with AngularJS, I was able to achieve this using ui-ace. Here is an example of how I did it: <textarea ui-ace="{ us ...

Halt scrolling news feed when hovering over with the mouse

I'm currently working on a news ticker on this jsfiddle, but it's not functioning as I'd like. Here are the issues I'm facing: When I increase the width and height of all the divs, it doesn't work properly as the last divs over ...

Utilizing Typescript to Incorporate Bable's Latest Feature: The 'Pipeline Operator'

Exploring the pipeline operator implementation in my Typescript project has been quite a journey. Leveraging babel as my trusty transpiler and Typescript as the vigilant type checker was the initial plan. The quest began with configuring babel to work sea ...

Using mongoDB to insert data followed by processing it with the process.next

Currently, I am in the process of inputting a list of 50k entries into my database. var tickets = [new Ticket(), new Ticket(), ...]; // 50k of them tickets.forEach(function (t, ind){ console.log(ind+1 + '/' + tickets.length); Ticket.find ...

Organizing a React Navigation App with a Visible Tab Bar

I have a clear image that demonstrates the problem https://i.sstatic.net/M2Hl7.png This is a simplified overview of the app structure. There is a tab bar navigator with three screens labeled A B C. TabBar A consists of a stack navigator containing D and ...

AngularJs and graph representation

After attempting to generate charts using angular-chart, I followed all the necessary steps and requirements outlined in the documentation. However, upon completion, my canvas element failed to display any content. My HTML Layout: Here is a snippet of my ...

Using Functional Programming with Node.js: A guide to waiting for a function to complete

As a newcomer to Node.js, I am satisfied with the syntax of JavaScript as I have utilized it for constructing web interfaces. With substantial experience in Object-Oriented Programming from Java and C#, along with an understanding of functional programming ...

Tips for incorporating PHP $_SESSION data into a JavaScript file

What I've been doing is using $_SESSION['siteRoot'] to store the root address of my website (since it's part of a framework and can vary depending on how the site is accessed). The challenge now is incorporating this value into some of ...

Somehow, my array only manages to traverse exactly half of its elements

Something odd is happening with my input tag in the HTML file where only half of my array elements are being processed. The input collects numbers/letters and assigns a line of code, like this: let result = Object.fromEntries( Object.entries(answers2).m ...

When a cross-domain iframe is loaded in a private browser, it automatically logs the user out

I've been collaborating with a client to create a unique standalone website on a subdomain. They have requested that I utilize their API to initiate a straightforward post request when a user clicks a button. However, the client prefers the user to ut ...

I am looking to display an image as a value in the dropdown menu of my Contact Form 7 on my WordPress website

I am currently working on a Wordpress website where I have a page showcasing 50 different company logos. Below the logo section, there is a form created using Contact Form 7. The logo section was built using a combination of HTML and CSS. Within the form ...

Is it possible to send an HTTP request from the renderer process to the main process in Electron?

Currently, I am in the midst of developing an electron video player project. My main objective is to stream video from a readable stream to an HTML video-tag. I am exploring different solutions and strategies to achieve this goal. In particular, I am cur ...

Sending a parameter from a click event to a function

Struggling with a jQuery and AJAX issue all night. I am new to both and trying to implement something similar to this example. I have an edit button with the ID stored in a data-ID attribute. Here's an example of what my button looks like: <butto ...

UPDATE: Choosing several classes and then toggling the classes independently for each one

I have managed to make this work, but I am considering if there is a more efficient solution. My objective is to modify the divs using classes exclusively. I aim to toggle 4 classes with just one click. First, I obtain the class for the button and then a ...

Sequencing asynchronous functions in Angular: Ensuring one function runs before another

When working with a save function that requires you to call another function to retrieve the revision number and make an API call, both of which are asynchronous in nature, how can you ensure one function waits for the other to execute? $scope.getRevision ...

Unexpected outcome when utilizing localeCompare options in Node.js

Comparing Output from CLI and Chrome Console: > var a = 'foo12'; undefined > var b = 'foo3'; undefined > var s = [a , b]; undefined > s.sort(function(a, b) { ... return a.localeCompare(b, 'en', { numeric: true }); ...