TypeScript | Objects with Unknown Keys and Known Values

Switching from JavaScript to TypeScript is often a blessing for JavaScript developers looking to get away from typical type definition errors creating unexpected behavior in code. Fortunately, this transition is for the most part straightforward and results in a very intuitive experience. However, there are scenarios that can be trickier than what you think, such as defining the type definition of an object with unknown keys and known value types, which I will show you how to do in this article.

Using Index Signatures

The best way to explain this is by presenting a coding case. Let’s say we want to have an object to store the numbers of the players on a soccer team. In theory, you might know the players at the moment. However, you won’t know the players in the future as every season some players are transferred to different teams or contracts are not renewed.

The keys of the object we will create will be a team players’ names. Their values will be their shirt number. We are going to define a interface with known property values and unknown property keys. The terminology for this is called is index signature and an example of using it will look like the following:

interface PlayersNumbers {
  [key: string]: number
}

Now, we can define a variable with this interface and add players with their respective numbers.

const machesterUnited:PlayersNumbers = <PlayersNumbers>{}; 

machesterUnited.davidDeGea= 1;
machesterUnited.paulPogba= 7;
machesterUnited.cristianoRonaldo = 7;
machesterUnited.marcusRashford = 10;

Index signatures can also work when defining a custom type. Instead of defining an interface called PlayersNumbers, you could define a custom type with the same name like the following:

type PlayersNumbers = {
  [key: string]: number
}

This should work without the need of making changes to the rest of the code.

Using Non-String Property Keys with Index Signatures

For those interested in assigning property keys with a type different than strings, there is only one type supported which is numbers. TypeScript does this not because they want to enforce it. Instead, in regular JavaScript you cannot have object keys different than strings, even though you could use a number as a property key like the following case:

const random = {};
random[1] = 'this is my first number';

At first, this is not what you think. We don’t have a number as a property key. We have a string as a property. This “number” key is converted to a string behind the scenes and it looks more like the following example:

random["1"] = 'this is my first number';

If you are interested in knowing more about this, I recommend this article which explains why JavaScript object keys are numbers or non-string values.

Since TypeScript allows to have string and number property types when using index signatures, we could run into situations where we will be overriding the values for a specific property.

interface AllPropertiesString {
  [key: number]: string;
  [key: string]: string;
}

const random: AllPropertiesString = <AllPropertiesString>{};
random[1] = 'This is the value for number 1';
random['1'] = 'This is a string';

console.log(random[1]); // will display 'This is a string'
console.log(random["1"]); // will display 'This is a string'

Therefore, it is recommended to define property keys as strings as they will be converted to strings at the end of the day.

More TypeScript Tips!

There is a list of TypeScript tips you might be interested in checking out

Did you like this TypeScript tip?

Share your thoughts by replying on Twitter of Become A Better Programmer or to personal my Twitter account.