When using ngFor, a conversion from a string literal type to a regular string occurs, resulting in an error that states: "Element implicitly has an 'any' type because an expression of type 'string' cannot be utilized..."

When utilizing the iterator *ngFor, it converts a string union literal type

("apple" | "banana")
to a string type. However, when attempting to use it as an index of an array expecting the correct string union literal type, an error occurs:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'FruitCollection'.

apple-banana-component.ts:

import { Component, OnInit } from '@angular/core';

const Fruits = ["apple", "banana"] as const;
type Fruit = typeof Fruits[number]; // "apple" | "banana"
type FruitCollection = { [fruit in Fruit]: number }; // {apple: number, banana: number}

@Component({
    selector: 'app-apple-banana',
    templateUrl: './apple-banana.component.html'
})
export class AppleBananaComponent implements OnInit {
    fruitBasket: FruitCollection = {
        apple: 10,
        banana: 10
    }
    fruitEaten: FruitCollection = {
        apple: 0,
        banana: 0
    }
    constructor() { }
    ngOnInit(): void { }
    eatFruit(fruit: Fruit) {
        this.fruitEaten[fruit]++;
        this.fruitBasket[fruit]--;
    }
}

apple-banana-component.html:

<div>
You have eaten {{fruitEaten['apple']}} apples and {{fruitEaten['banana']}} bananas.

<div *ngFor="let fruit of fruitBasket | keyvalue">
    {{fruit.key}}: 
    {{fruit.value}} in basket, 
    {{fruitEaten[fruit.key]}}    
    eaten.
    <button (click)="eatFruit($any(fruit.key))">eat {{fruit.key}}</button>
</div>
</div>

Oddly enough, $any(fruit.key) works inside eatFruit() but not within fruitBasket[].

{{fruitEaten[fruit.key as Fruit]}}

{{fruitEaten[fruit.key as keyof typeof fruitEaten]}}

{{fruitEaten[$any(fruit.key)]}}

Answer №1

Posting an answer to share a solution that has successfully worked for me. While the workaround suggested by Tobias S. is effective, it involves creating a new function. An alternative approach is to iterate over the constant Fruits:

import { Component, OnInit } from '@angular/core';

const Fruits = ["apple", "banana"] as const;
type Fruit = typeof Fruits[number]; // "apple" | "banana"
type FruitCollection = { [fruit in Fruit]: number }; // {apple: number, banana: number}

@Component({
    selector: 'app-apple-banana',
    templateUrl: './apple-banana.component.html'
})
export class AppleBananaComponent implements OnInit {
    fruits = Fruits;
    fruitBasket: FruitCollection = {
        apple: 10,
        banana: 10
    }
    fruitEaten: FruitCollection = {
        apple: 0,
        banana: 0
    }
    constructor() { }
    ngOnInit(): void { }
    eatFruit(fruit: Fruit) {
        this.fruitEaten[fruit]++;
        this.fruitBasket[fruit]--;
    }
}

It's interesting that iterating over

fruits of Fruits = ["apple", "banana"]
rather than over fruitBasket[] helps maintain the string literal union type within *ngFor, thereby preventing any type errors.

<div *ngFor="let fruit of Fruits">
    {{fruit}}: 
    {{fruitBasket[fruit]}} in basket,
    {{fruitEaten[fruit]}} eaten.
    eaten.
    <button (click)="eatFruit(fruit)">eat {{fruit}}</button>
</div>

Although the reason behind this behavior remains uncertain, the method proves to be effective.

Answer №2

The issue at hand is that the key generated by the keyvalue always results in a string. Using a string as an index for your type is not feasible, and unfortunately, type assertions are not allowed in templates. While using $any seemed promising, even any cannot be used to index object types without index signatures when noImplicitAny is set to true.

To address this, one solution is to create a function within your component for the casting process.

apple-banana-component.ts

public isFruit(value: string): Fruit {
  return value as Fruit
}

You can then utilize this function within your template code.

<div *ngFor="let fruit of fruitBasket | keyvalue">
    {{fruit.key}}: 
    {{fruit.value}} in basket, 
    {{fruitEaten[isFruit(fruit.key)]}}
    eaten.
    <button (click)="eatFruit(isFruit(fruit.key))">eat {{fruit.key}}</button>
</div>

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

Is it possible to designate a Typescript generic type as a tuple with equal length to that of another tuple?

Imagine having a function that takes in a dataset which is an array of (identically-typed) tuples: type UnknownTuple = any[] function modifyDataStructure<T extends UnknownTuple>(list: T[]) { ... } The goal is to define a second argument with the ...

Ways to add parameters to each external URL using Angular

Seeking thoughts on implementing a feature in Angular to append a parameter to all external URLs or URLs from a specific domain. Let's take as an example. If I were using jQuery, I could achieve this on document ready by doing something like: $(‘ ...

"Enhance your development experience with the TypeScript definitions for the Vue 2 plugin

Currently, I am utilizing VSCode alongside TypeScript classes for developing Vue 2 components. You can check out more information at: vuejs/vue-class-component. Within my present project, I make use of plugins like vue-i18n for handling translations of la ...

A guide on incorporating a single class object of type Observable<any> into HTML

I'm currently working with Angular4 and have a Windows Timer subscribed observable in my typescript file. this.dynamicTime = new Observable<string>((observer: Subscriber<string>) => { setInterval(() => observer.next(this ...

Retrieving Values from Components in Angular 6

Encountering an issue while retrieving values from different components. The scenario involves 2 components - ReceiveBookingManageComponent as the first component and DriverTablePickerComponent as the second one. The problem arises in DriverTablePickerCo ...

The style fails to load correctly upon the page's initial loading

I am utilizing <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="4d26282823603e212429283f0d7b63756378">[email protected]</a> in a <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="026c677a76 ...

Angular 7 with JQWidgets - How to Export Grid data from a different component

Currently, I am working on integrating Angular 7 with JQWidgets. My focus is on the Grid component and my goal is to export data from the Grid in another component called settings. I followed a demo (accessible here) and created the component below: impor ...

Updating the main window in Angular after the closure of a popup window

Is it possible in Angular typescript to detect the close event of a popup window and then refresh the parent window? I attempted to achieve this by including the following script in the component that will be loaded onto the popup window, but unfortunatel ...

Ways to speed up the initial loading time in Angular 7 while utilizing custom font files

Storing the local font file in the assets/fonts folder, I have utilized 3 different types of fonts (lato, raleway, glyphicons-regular). https://i.stack.imgur.com/1jsJq.png Within my index.html under the "head" tag, I have included the following: <lin ...

Converting the 'require' call to an import may be a more efficient method when importing package.json in a typescript file

In my current project, I am creating a class where I am directly accessing the package version number like this: const pkg = require('../package.json') export class MyClass() { constructor() { // Set the base version from package.jso ...

Explain the functionality of the Angular EventListener that is triggered on the scroll event of

Currently, I am exploring ways to track the position of the navbar beneath the landing page. The goal is for the navbar to become sticky at the top once it reaches that position until you scroll back up. Despite trying various solutions on Stack Overflow a ...

Obtaining the identifier of a generic type parameter in Typescript

Is there a method in TypeScript to retrieve the name of a generic type parameter? Consider the following method: getName<T>(): string { .... implement using some operator or technique } You can use it like this: class MyClass{ } getName< ...

The logic behind regular expressions

Currently working on building a web application with Angular 6 and I have a query: I'm in the process of developing a custom input component (specifically for text inputs) like so: @Component({ selector: 'input-text', templateUrl: &apos ...

Unable to access structuredClone on the global object within a Node.js application

structuredClone is causing issues in my NodeJS application. Whenever I try to utilize it, I encounter the error: structuredClone is not defined nodejs. To troubleshoot, I created a simple file and executed the following: console.log({ globals: Object. ...

What is the reason for the index type being defined twice?

Here is an example from the official TypeScript documentation: class Animal { name: string; } class Dog extends Animal { breed: string; } // Error: indexing with a 'string' will sometimes get you a Dog! interface NotOkay { [x: numbe ...

I require all of this to be brought back as one complete entity. If, for instance, the object is given the value 10/26, it should be interpreted as part of the input

I am facing an issue with my Angular + .NET Application where the search method is not recognizing a specific ConsumerUnit when the input includes a / character. Currently, if I input something like 10/2689123, the application treats the / as part of the ...

Explore an example of using custom controls in a FormArray within an Angular 5 reactive form on StackBlitz

Check out my sample project on stackblitz that tests nesting components and retrieving the complete form value. https://stackblitz.com/edit/mensand-hobbies-football-tennis This is a demonstration where I aim to utilize different components stored in an a ...

Utilizing event bubbling in Angular: a comprehensive guide

When using Jquery, a single event listener was added to the <ul> element in order to listen for events on the current li by utilizing event bubbling. <ul> <li>a</li> <li>b</li> <li>c</li> <li>d< ...

Retrieve an item from an Angular 2 Observable Dataservice

I'm new to using Observables in Angular 2 and I have a query. In my data service class, there is a method called getExplorerPageData which sends an http request returning a data structure containing several arrays. I want to create another function n ...

Is it possible to duplicate a response before making changes to its contents?

Imagine we are developing a response interceptor for an Angular 4 application using the HttpClient: export class MyInterceptor implements HttpInterceptor { public intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<an ...