TypeScript | Objects with Unknown Keys and Known Values

Switching from JavaScript to TypeScript is often a bless for JavaScript developers looking to get away from typical types definition errors creating unexpected behavior in code. Fortunately, this transition is for the most part straightforward and results into 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 of 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 an 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 an 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 are 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 explaining why JavaScript object keys be 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.

Share this article or checkout our social media channels!