Objects 16 exercises
Problem

Supporting Different Types of Keys in TypeScript

Consider this hasKey function that accepts an object and a key, then calls object.hasOwnProperty on that object:


const hasKey = (obj: object, key: string) => {
return obj.hasOwnProperty(key);
}

The function isn't particularly useful since it's just an abstraction over `has

Loading exercise

Transcript

00:00 In this exercise we have a hasKey function that takes in an object and then also takes in a key. Then it calls object.hasOwnPropertyKey on that object. Cool, simple enough. So it's kind of like an abstraction over hasOwnProperty. It's a little not particularly useful, this function,

00:19 but it really demonstrates something interesting, which we'll see below. We have a couple of test cases. It should work on string keys. Okay, we have an object with a string key of foo, and then the value is bar. And it should say expect hasKey object foo to be true, and expect hasKey object bar to be false. Great, that's all working.

00:38 Beautiful stuff. But if we go further down, you'll see it doesn't work on numeric keys. So we've got in a type error when we call hasKey object, this object has one as the key, and then basically we're passing in bar as the value here. So we're expecting it to have a key of one,

00:55 but argument of type number is not assignable to parameter of type string. We go further down, we're doing something with symbols as well. Symbols are a JavaScript feature that declare a kind of unique symbol here, returns a new unique symbol value on the symbol. And so we can create a foo symbol, which can be a key you can pass to an object. This is valid JavaScript too.

01:15 And then we can check if it's a foo symbol or a bar symbol here. And these are symbols down at the bottom here. So your job is to work out how we can better type this key, because if you look at the tests, everything's all passing and working fine, but this type annotation of string seems too narrow for what we want.

01:32 And there's an obvious answer, but there's also a cool answer. And I would like you to try and find the cool answer, which is there is a global type available in TypeScript that lets you represent all of these possibilities. Good luck.