Skip to content

Commit 3f3fa3f

Browse files
committed
More objects review
1 parent a71d271 commit 3f3fa3f

File tree

1 file changed

+38
-12
lines changed

1 file changed

+38
-12
lines changed

book-content/chapters/06-objects.md

+38-12
Original file line numberDiff line numberDiff line change
@@ -445,13 +445,11 @@ interface Product extends WithId, WithCreatedAt {
445445

446446
We've now refactored our intersections to use `interface extends` - our TypeScript compiler will thank us.
447447

448-
<!-- CONTINUE -->
449-
450448
## Dynamic Object Keys
451449

452450
When using objects, it's common that we won't always know the exact keys that will be used.
453451

454-
In JavaScript, we can start with an empty object and add keys and values to it as we go:
452+
In JavaScript, we can start with an empty object and add keys and values to it dynamically:
455453

456454
```typescript
457455
// JavaScript Example
@@ -462,7 +460,7 @@ albumAwards.MercuryPrize = false;
462460
albumAwards.Billboard = true;
463461
```
464462

465-
However, when we try to add keys to an empty prototype object in TypeScript, we'll get errors:
463+
However, when we try to add keys dynamically to an object in TypeScript, we'll get errors:
466464

467465
```typescript
468466
// TypeScript Example
@@ -473,32 +471,58 @@ albumAwards.MercuryPrize = false; // red squiggly line under MercuryPrize
473471
albumAwards.Billboard = true; // red squiggly line under Billboard
474472

475473
// hovering over Grammy shows:
476-
Property 'Grammy' does not exist on type '{}'.
474+
// Property 'Grammy' does not exist on type '{}'.
477475
```
478476

479-
TypeScript is protecting us from adding keys to an object that doesn't have them defined.
477+
This can feel unhelpful. You might think that TypeScript, based on its ability to narrow our code, should be able to figure out that we're adding keys to an object.
478+
479+
In this case, TypeScript prefers to be conservative. It's not going to let you add keys to an object that it doesn't know about. This is because TypeScript is trying to prevent you from making a mistake.
480480

481481
We need to tell TypeScript that we want to be able to dynamically add keys. Let's look at some ways to do this.
482482

483483
### Index Signatures for Dynamic Keys
484484

485-
Index signatures are one way to specify we want to be able to add any key and value to an object. The syntax uses square brackets, just like we would if we were adding a dynamic key to an object literal.
485+
Let's take another look at the code above.
486486

487-
Here's how we would specify an inline index signature for the `albumAwards` object literal. We'll call the key `award` as a string, and specify it should have a boolean value to match the example above:
487+
```typescript
488+
const albumAwards = {};
489+
490+
albumAwards.Grammy = true; // red squiggly line under Grammy
491+
```
492+
493+
The technical term for what we're doing here is 'indexing'. We're indexing into `albumAwards` with a string key, `Grammy`, and assigning it a value.
494+
495+
To support this behavior, we want to tell TypeScript that whenever we try to index into `albumAwards` with a string, we should expect a boolean value.
496+
497+
To do that, we can use an 'index signature'.
498+
499+
Here's how we would specify an index signature for the `albumAwards` object.
488500

489501
```typescript
490502
const albumAwards: {
491-
[award: string]: boolean;
503+
[index: string]: boolean;
492504
} = {};
505+
506+
albumAwards.Grammy = true;
507+
albumAwards.MercuryPrize = false;
508+
albumAwards.Billboard = true;
493509
```
494510

495-
Note that with the inline index signature above, the values must always be a boolean. The `award` keys we add can't use a string or any other type.
511+
The `[index: string]: boolean` syntax is an index signature. It tells TypeScript that `albumAwards` can have any string key, and the value will always be a boolean.
512+
513+
We can choose any name for the `index`. It's just a description.
514+
515+
```typescript
516+
const albumAwards: {
517+
[iCanBeAnything: string]: boolean;
518+
} = {};
519+
```
496520

497521
The same syntax can also be used with types and interfaces:
498522

499523
```typescript
500524
interface AlbumAwards {
501-
[award: string]: boolean;
525+
[index: string]: boolean;
502526
}
503527

504528
const beyonceAwards: AlbumAwards = {
@@ -507,7 +531,9 @@ const beyonceAwards: AlbumAwards = {
507531
};
508532
```
509533

510-
Index signatures are one way to handle dynamic keys, but there's a more readable way to do this with a type we've seen before.
534+
Index signatures are one way to handle dynamic keys, but there is a very popular type helper which is often preferred.
535+
536+
<!-- CONTINUE -->
511537

512538
### Using a Record Type for Dynamic Keys
513539

0 commit comments

Comments
 (0)