Dealing with a nested object problem in Angular using TypeScript

I am currently working on an Angular 15 application that is designed to showcase information about different games to users.

Within the application, I have a global object structured like this:

GAMES_INFO: {
    skyroads: {
        name: 'Sky Roads',
        genre: GAMES_GENRES.action,
        year: 1993,
        wiki: 'https://en.wikipedia.org/wiki/SkyRoads_(video_game)',
    },
    prehistorik2: {
        name: 'Prehistorik 2',
        genre: GAMES_GENRES.arcade,
        year: 1993,
        wiki: 'https://en.wikipedia.org/wiki/Prehistorik_2',
    },
}

My goal is to display game data to the user once they select a specific game:

Currently, using

this.gameInfo = dic.GAMES_INFO['skyroads'];
works perfectly. However, I would like the user to input the game name like this:
this.gameInfo = dic.GAMES_INFO[gameName];
(where gameName is a string)

Attempting this approach results in the error message

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

Can anyone provide guidance on how to resolve this issue?

Answer №1

The reason is that the GAMES_INFO object keys are restricted to skyroads and prehistorik2, while the gameName can have any string value, making it more versatile.

You can choose one of these options:

  1. Specify gameName with GAMES_INFO key list
let gameName: keyof typeof GAMES_INFO; // only keys of GAMES_INFO object are valid as values

// the following line will not work 
// since "hello world" is not a key in GAMES_INFO
gameName = 'hello world'; // Type '"hello world"' is not assignable to type '"skyroads" | "prehistorik2"'

gameName = 'prehistorik2'; // this will work
  1. Convert GAMES_INFO type to any
gameInfo = (GAMES_INFO as any)[gameName];
  1. Convert gameName type to key of GAMES_INFO
gameInfo = GAMES_INFO[gameName as keyof typeof GAMES_INFO];

If you need to get gameName from the user, ensure that you restrict the available choices to only GAMES_INFO keys and validate the user's selection:

if(gameName in GAMES_INFO){
    console.log('ok')
}else{
    console.log('error');
}

In summary, (1) type correctly, (2) limit user input options, and (3) validate the user's input.

Answer №2

The reason for this issue is that when you attempt to access a property of an object in Typescript, it lacks the ability to iterate over the keys of that object.

A potential solution is to define your general object using an interface and then utilize

this.gameInfo = dic.GAMES_INFO[gameName as keyof ObjectType]; where ObjectType represents the interface's name.

However, if frequent additions and removals of keys/values are necessary, utilizing Map() is advisable.

In my personal opinion, working with a map is also more user-friendly.

For additional clarification, please refer to the mdn web docs:

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map

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

Utilizing Typescript and RequireJS for Incorporating jqueryui

Recently, I've been encountering issues with getting jQueryUI to function properly. Strangely enough, prior to attempting to integrate jQueryUI, using jQuery alone worked perfectly fine. The current problem I'm facing is receiving a "TypeError: ...

How to use Angular2 Router to redirect a state to its default substate

How can we implement a default substate in the new Angular2 Router? For instance, I would like the router to automatically direct from /user to /user/profile, creating a default substate for user. ...

Directive for multi-field validation in Angular 4 Template-Forms with ngModelGroup

Can someone assist me in validating the match between a user's new password and confirm password using an Angular Directive? Despite correctly identifying a mis-match, the error message is not displayed: Template Form <form> <md-input- ...

What is the ternary operation syntax for setting the img src attribute in Angular 8?

My data includes a property called "photo" which can either have a file name or be empty. For instance, it could be "steve.jpg" or just an empty string if Steve does not have a photo. In React JSX, I know how to use a ternary operator with the "photo" va ...

Unable to allocate information in the subscribe method

I'm experiencing an issue with the post method. Whenever I try to retrieve data using the segmentService, I always receive an empty segmentdata object in my temporarySegment variable. Strangely enough, when I use the same approach for retrieving numbe ...

Angular 12 isn't showing any providers available for HttpHeaders

Encountering an error when attempting to utilize the get and post methods within a component. Trying to extend proved futile as HttpClient is marked as final. Even after trying to extend, the same error persists. ERROR Error: Uncaught (in promise): NullI ...

Error Raised Due to Modification After Checking in Angular 2/Angular 5

Dealing with ExpressionChangedAfterItHasBeenCheckedError in Angular 2/Angular5 Error message: An error has occurred: ExpressionChangedAfterItHasBeenCheckedError. The expression has changed after it was checked. Previously it was 'ng-untouched: ...

Using Partial function input in TypeScript

I am in need of a function that can accept partial input. The function includes a variable called style, which should only have values of outline or fill, like so: export type TrafficSignalStyle = 'outline' | 'fill' let style: TrafficSi ...

The variance in module types within the tsconfig.json file

When configuring your project in tsconfig.json, you may come across the following options: { "compilerOptions": { "target": "es5", "module": "commonjs", "moduleResolution": "node", "sourceMap": true, "emitDecoratorMetadata": t ...

syncfusion export pdf demonstrating the toggle button's current state

Currently, I am using syncfusion for converting my page to PDF format. I have a toggle button that is default set to true. However, regardless of the actual state of the toggle button, it always appears as on (true) when exported to PDF. I attempted to s ...

Is there a way to view the console in a released apk?

Currently working with Ionic and in need of exporting a release APK to be able to monitor the console for any potential issues. I am aware that using 'ionic cordova run --device' allows me to view the console, but it only shows a debug APK. Is t ...

AngularJS and CSS: A Guide to Effortlessly Toggle Sliding List Elements

I am in the process of developing a drop-down menu that can be clicked. Using my custom AngularJS directive, I have successfully implemented functionality to load menu items dynamically. While I have made significant progress, I have encountered a small i ...

Breaking up React code within the React.createElement() function

I am encountering an issue with lazily loaded pages or components that need to be rendered after the main page loads. When using createElement(), I receive the following error: LazyExoticComponent | LazyExoticComponent is not assignable to parameter of ty ...

Tips for preventing words from being split between lines in an error message

I am encountering a problem in Angular 2 where error messages are being split onto two lines when there isn't enough space for the entire word. Check out this screenshot for reference Is it possible to prevent words from being divided across lines? ...

Angular 2+ Service for tracking application modifications and sending them to the server

Currently I am facing a challenge in my Angular 4 project regarding the implementation of the following functionality. The Process: Users interact with the application and it undergoes changes These modifications are stored locally using loca ...

Is it possible to select a tab in Angular 10 Material Tabs based on a route parameter?

My webpage features a mat-tab-group, located at the URL /transactions. <mat-tab-group> <mat-tab label="Shipments"> <ng-template matTabContent> shipment content </ng-template> ...

Guide to successfully passing a function as a prop to a child component and invoking it within Vue

Is it really not recommended to pass a function as a prop to a child component in Vue? If I were to attempt this, how could I achieve it? Here is my current approach: Within my child component - <template> <b-card :style="{'overflow-y&apo ...

problem encountered while attempting to drag and drop list elements on a web application utilizing dhtmlx 5.0 and wijmo grid

My web application utilizes Dhtmlx 5.0, Wijmo grid, and Typescript. One feature of the app is a dialog box that displays a list of items which can be rearranged using drag and drop functionality. This feature works without any issues on Windows PCs but enc ...

Having trouble retrieving the chosen option from a select box in Angular 8

I'm working with a dynamic array and I need to generate a select box based on its values. Additionally, I want to pre-select the option that corresponds to the value defined in the array. { "data": [ { "player settings": [ { ...

Error message: While running in JEST, the airtable code encountered a TypeError stating that it cannot read the 'bind' property of an

Encountered an error while running my Jest tests where there was an issue with importing Airtable TypeError: Cannot read property 'bind' of undefined > 1 | import AirtableAPI from 'airtable' | ^ at Object.&l ...