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.
Table of Contents
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 number
s. 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 string
s 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
- TypeScript | The Unknown Type Guide
- TypeScript | Organizing and Storing Types and Interfaces
- TypeScript | Double Question Marks (??) – What it Means
- TypeScript | Union Types – Defining Multiple Types
- TypeScript | Declare an Empty Object for a Typed Variable
- TypeScript | Union Types vs Enums
- TypeScript | Convert Enums to Arrays
Did you like this TypeScript tip?
Share your thoughts by replying on Twitter of Become A Better Programmer or to personal my Twitter account.