Hey there, TypeScript enthusiast! Working with TypeScript, chances are you’ve come across the intriguing “unknown” type. It’s like that enigmatic puzzle piece that doesn’t reveal its true nature until you’ve cracked the code. Well, consider this article your ultimate decoder ring, as we dive headfirst into the captivating realm of converting TypeScript’s “unknown” type into a type that plays nice with the rest of your codebase.
What is Unknown?
The unknown type is just as it sounds – it means TypeScript has absolutely no idea what type your variable is, and therefore it won’t let you do anything with it, since it doesn’t know if you can. It’s a compliment to the “any” type. Any is very similar, the key difference is TypeScript will trust you to do anything to your variable, essentially breaking out of TypeScript and back into typeless JavaScript land.
We can see this here:
let unknownValue: unknown;
let anyValue: any;
unknownValue.foo; //TS18046: 'unknownValue' is of type 'unknown'
unknownValue += 1;//TS18046: 'unknownValue' is of type 'unknown'
anyValue.foo; //✅ Works
anyValue += 1; //✅ Works
An unknown type throws an error whenever you try to do anything to it, whereas an any type doesn’t care. It’s the difference between TypeScript saying “I don’t know what type this is so I don’t trust what it can do”, and “I don’t know what type this is, so I’ll trust you know what it can do”.
The Unsafe Way
The easiest way to convert your type from “unknown” is through casting the variable:
function double(value: unknown) {
//I hope it's a number
return (value as number) * 2;
}
Here we have a simple function to double a number. Since we cast our value to a number, TypeScript will then treat it as a number, which lets us use the multiplication operator with it.
This lets us do something like this:
console.log(double(10)); //Works
console.log(double({ value: 10 })); //Works, but should it?
But obviously multiplying an object doesn’t make sense. The output is what you’d expect:
The first value works, but with the second one, TypeScript tries to convert the object to a number under the hood, which obviously doesn’t work, so we get NaN.
The Safe Way
Casting the type is an easy way of forcing TypeScript to get rid of the unknown, but in a lot of scenarios, your code will break if the type is wrong. This is where type narrowing and type guards come into play. Instead of forcing the type, we can check the type. There are a lot of ways to do this in TypeScript, but with a primitive like “number”, we can use the typeof operator:
function double(value: unknown) {
if (typeof value !== 'number') return;
//Now I know I have a number
return value * 2;
}
So why does this work? It’s simple. If our value isn’t a number, then we end up returning on the first line of the function. This means TypeScript can be sure your value is a number in the line after, since we only get to that line when value is a number.
Running the code again, here’s the output:
In my case I’ve decided to just return nothing if the value isn’t a number. What you do might depend on your use case, e.g. if the value is a response from an API, you may want to throw an error to show that you’ve received an unexpected response.
Conclusion
Thanks for reading! I hope this article was a good introduction to the unknown type in TypeScript, and hopefully you’re now equipped with the knowledge of how to get rid of the unknown type. As I said earlier the type is very similar to “any”, but in my opinion if you’re looking to be strict with your types, I’d suggest picking unknown over any. It may seem like a pain that adds boilerplate, but the type helps us to integrate unknown values into TypeScript’s type safety system. With all that said, if you liked this article, or if you had any issues, feel free to leave a comment below!
💬 Leave a comment