Narrowing Unknown Types in TypeScript
Here's our starting point:
const parseValue = (value: unknown) => { if (true) { return value.data.id; // red squiggly line under `value` } throw new Error("Parsing error!");};
To fix the error, we'll need to narrow the type using conditional checks. Let's take it ste
Transcript
00:00 Okay, let's do it. We first of all need to know if type of value equals object. If it's an object, then we can do business with it. We know that it's probably got a data attribute. And let's next check if there's a data attribute in value here. So okay, this is we've got
00:17 the same error that's happening down the bottom here, but we've also got an error here saying value is possibly null. That's because we've got object here or null. It doesn't know from this check, gee thanks JavaScript, whether value is an object or whether it's null. So
00:32 we have to check it. We have to say and value even before we do this check here. So even in the check itself, TypeScript will ensure that sequentially we're not doing anything illegal. So that's good. We're now checking if it's like if it's null or not. We could
00:48 even do if value not equal to null just for clarity. And now we need to go deeper. So we know now that value is an object and it's got this attribute of record data unknown. We hover over data now, it's a type unknown. So let's start narrowing that. The unknowns
01:04 are just sort of spreading out. So now we need to say and type of value dot data is an object. And we probably need to do this same check again. And value dot data not equal
01:19 to null. Very good. Now we're getting this ID attribute because again that one doesn't exist. So we can now check if ID in value dot data. And finally, so there's finally not an error here, but I added a return type just to make sure that we're returning string.
01:38 If I remove that, you can see that currently we're returning unknown from our pass value function. So what we need to do is we need to finally check if value dot data dot ID
01:51 is a string. Let's add that. If type of value dot data dot ID equals string. Beautiful. Now if we hover over pass value, you can see that it's a function that takes in unknown and always returns a string. Because if this check fails, we actually throw an error, meaning
02:09 it doesn't resolve and it cuts out that part of the of the return type. So now checks are working beautifully. Our tests should be passing as well. And it means we're home free. Now this is ugly, ugly code, right? If I was to do this in production, I would probably use
02:25 a library called Zod instead, for which I've got a free tutorial on this site too. And this would be a lot simpler and just be a single line of code using Zod. But knowing that you can do this, I think is a really nice exercise to understand that TypeScript has your back when you're doing this kind of narrowing. And unknown really is just like
02:43 a massive union type of all of the possible things there are in TypeScript. And so if you know how to narrow unknown, then you're probably going to have a pretty easy job narrowing something that's a little bit clearer.