Techniques for Typing Dynamic Object Keys
This is another challenge with multiple solutions.
Use the Record Utility Type
One solution is to type cache
as a Record
:
const cache: Record<string, string> = {}
The first type argument to Record
is for the key, and the second is for the value. In our case, both are s
Transcript
0:00 This problem has multiple solutions. We've got a type here which I've added to this cache here. What that appears to be doing is it appears to be allowing us to save anything on that cache. We can do anything here. We can say cache dot blah, blah, blah, blah, blah equals something cool here.
0:25 What it's allowing us to do is then access things off that cache later, too. We can do cache.cache 23 to equal undefined. This type here, what that's describing is, basically, it allows us to add any number of dynamic keys to that object at runtime. That's what a record type is.
0:48 This is different from a set and a map that we saw in the previous exercise, because it's just at the type level. It's just saying that this object here can contain any keys that we want, but they have to be strings. We can't pass numbers here, Booleans, or anything like that. This is one way to express this.
1:09 What you might have seen in the exercise here is that you had index types everywhere. It was saying, "You can't index this, can't use that to index this." This is saying basically that if we were to untie this record type, what it's saying is that this here is the index of the objects, the key of the object. Whenever you see index in a type error, it's usually referring to the key of an object.
1:39 What this is saying here is that instead of using record string here, we've used this syntax that says the key of this object, we can say index string, and then you get the value afterwards, too. I can rename this to a number if I want to as well.
1:57 Inside this cache, everything would have to be cache 1 equals value. That's an alternative way of expressing that. This is what's called an index signature inside a type. Now, we can express this in a third way, too, by using an interface. Interface can use these index signatures, too.
2:15 Whichever solution you found, or if you found a solution, record interface or this in-line type here, and I can also extract this out to a type if I want to type blah equals this and then cache is blah. Whichever solution you found -- index string just to make those errors go away -- then it doesn't really matter. There's no pros and cons over either one of these solutions. They're just alternatives.
2:41 Usually, record is a little bit easier to look at and easier to pass what it's doing. It also comes with a little descriptor of what it's doing, too. Any of these things can be used to construct different caches. Of course, I can change this second property to anything I want to. I can be like a 1 or a number, etc. I can throw anything in there.
3:04 A really common pattern in JavaScript is assigning things to an object with dynamic keys, and this allows you to do it.