Reading a value by its key
A dictionary maps keys to values, and you read a value by giving its key. In TypeScript, a dictionary is usually an object, and there are two ways to read from it: bracket notation and dot notation.
const scores: { [key: string]: number } = {"Alice": 95, "Bob": 87, "Charlie": 72};
let aliceScore: number = scores["Alice"]; // 95 (bracket notation)
let bobScore: number = scores.Bob; // 87 (dot notation)
The type { [key: string]: number } says that the keys are strings and the values are numbers. Both reads give back a number, and each returns the value stored under that key.
Brackets or dot
Bracket notation takes any expression that evaluates to a string, so it works for every key. Dot notation takes a name written directly in the code, so it works only when the key is a valid identifier: letters, digits, _ and $, not starting with a digit.
const info: { [key: string]: string } = {"first name": "Ada", "city": "London"};
console.log(info["first name"]); // Ada
console.log(info.city); // London
// info.first name is a syntax error: the space ends the name
Brackets are also the only choice when the key is stored in a variable. A dot always means the literal name that follows it:
const scores: { [key: string]: number } = {"Alice": 95, "Bob": 87};
const student = "Bob";
console.log(scores[student]); // 87
console.log(scores.student); // undefined: looks for a key named "student"
Keys that are missing
Reading a key that isn't in the object doesn't throw an error. It gives undefined:
console.log(scores["Diana"]); // undefined
The compiler still treats the result as a number, because the type only says what values the dictionary holds, not which keys exist. Arithmetic on the result gives NaN instead of failing, so a missing key is easy to miss. Keep two ways to check in mind:
- The
inoperator asks whether the key exists:"Alice" in scoresistrueand"Diana" in scoresisfalse. - Comparing with
undefinedworks too:scores["Diana"] === undefinedistrue.
if ("Alice" in scores) {
console.log(scores["Alice"]); // 95
}
There is one subtlety. The in operator also finds names that every object inherits, so "toString" in scores is true even though you never added that key. To ask only about keys you stored, use Object.hasOwn(scores, "toString"), which is false here. For ordinary names such as people's names the two checks agree.
A default for missing keys
Often you want a fallback value instead of undefined. The nullish coalescing operator ?? supplies one: a ?? b is b only when a is undefined or null.
const scores: { [key: string]: number } = {"Alice": 95, "Bob": 87};
console.log(scores["Diana"] ?? 0); // 0
console.log(scores["Alice"] ?? 0); // 95
Prefer ?? to || here. A stored score of 0 is a real value, and || would treat it as missing and replace it with the default, while ?? keeps it.
To visit every entry, loop over the keys and read each value by its key:
for (const name of Object.keys(scores)) {
console.log(name, scores[name]);
}
This prints Alice 95 and then Bob 87. The keys come out in the order they were added, for ordinary names like these. Inside the loop every key exists, so each read is safe, and the variable name holds a string, which is exactly what brackets expect.
The lesson's exercise
The starting code already declares the dictionary scores. The task is to read Alice's score into a new variable.
- Declare the variable below the dictionary. It holds a score, so give it the type
numberand the namealiceScore. - Read the value with
scores["Alice"]and assign it.
const scores: { [key: string]: number } = {"Alice": 95, "Bob": 87, "Charlie": 72};
let aliceScore: number = scores["Alice"];
After this line, aliceScore holds 95. It is a copy of the number, so changing aliceScore later doesn't change the dictionary.
Gotchas
- Case matters.
scores["alice"]andscores["Alice"]are different keys, and the first one isundefinedhere. - The quotes in brackets matter.
scores[Alice]without quotes looks for a variable namedAlice, not the string. - Spelling errors don't crash. A mistyped key quietly gives
undefined, so a surprisingundefinedorNaNis a hint to check the key. - Keys are strings. For an object,
scores[1]andscores["1"]read the same entry.
Key takeaways
- Read a value with
obj["key"], or withobj.keywhen the key is a simple name. - Only brackets accept keys with spaces or special characters, and keys held in variables.
- A missing key reads as
undefined, not as an error. - Use
"key" in objto test whether a key is present.