0

I have an Angular 15 application which shows games information for users.

I have a global object that look something 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',
    },
}

And I want to display data to the user once he selects a game:

Doing the following works well this.gameInfo = dic.GAMES_INFO['skyroads'];

But, I would like the game name to be an input from the user like this: this.gameInfo = dic.GAMES_INFO[gameName]; (gameName is a string) This result in an the following error TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used to index type.

How do can I fix that?

Yoni Mayer
  • 1,212
  • 1
  • 14
  • 27

2 Answers2

1

This is because you're trying to access a property of an object, Typescript doesn't know how to iterate over the keys of that object.

One solution would be to type your general object with an interface and then do

this.gameInfo = dic.GAMES_INFO[gameName as keyof ObjectType]; where ObjectType is the name of the interface.

Tho if you will have to do frequent additions and removals of your keys/values. I would recommend using a Map().

In my personal opninion a map is also easier to work with.

For some more explanation I've added the mdn web docs:

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

LeKeque
  • 21
  • 4
1

It's because GAMES_INFO object keys are limited to skyroads and prehistorik2 but the gameName could have any string value, which is much more generic than that.

You can try one of these:

  1. Type gameName with GAMES_INFO key list
let gameName: keyof typeof GAMES_INFO; // only the keys of GAMES_INFO object will be accepted as value

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

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

As you want to get gameName from the user, it's important that you limit the available options only to GAMES_INFO keys and also validate user choice:

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

In resume, (1) you have to type correctly, (2) limit user input and (3) validate the input from user

Jonas Ruth
  • 69
  • 5
  • regarding the first option you provided, what is the meaning of `!` after `gameName`? – Yoni Mayer May 16 '23 at 06:19
  • Sorry, there was no need for the "!" in this case. I'll update my response. But for your knowledge see this related question: https://stackoverflow.com/questions/42273853/in-typescript-what-is-the-exclamation-mark-bang-operator-when-dereferenci – Jonas Ruth May 29 '23 at 19:20