Type Assertions, Trucks, and Aliens
about14sheep
Posted on December 4, 2022
Buckle up, yo.
I'm listening to R&B right now
It's extremely early where I am, and I couldn't sleep. So like any logical person would be doing, I was reading through the TypeScript Handbook. As I am reading the part about type assertions (the as
keyword); I couldn't help but think back to a StackOverflow answer I wrote about multiple type assertions. Don't get me wrong, I like my answer. However, it's just that its... well its...
While laying there I had an epiphany, the likes of which would make every Ancient Astronaut Theorist proud. I could spice up the explanation of type assertions (and make it more understandable) if I added aliens.
What even is TypeScript?
If you don't know what TypeScript is, you should. That's all I have to say about that.
Type Assertions
Now that it's just the TS nerds; lets talk about Type Assertions. In short (because obviously I am going to explain it WAY cooler further down), a type assertion is you telling the compiler whats up. The compiler isn't the great Giorgio A. Tsoukalos, sometimes you just know better. Type Assertions allow you to tell the compiler that a particular type will behave like another (i.e. have the same shape). I won't bog us down with code yet, and the handbook has a great example so i'll just steal that:
For example, if you’re using
document.getElementById
, TypeScript only knows that this will return some kind ofHTMLElement
, but you might know that your page will always have anHTMLCanvasElement
with a given ID.In this situation, you can use a type assertion to specify a more specific type:
const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;
That's all well and good, pretty easy to understand. However, there are obvious limitations to this. What if I tried to tell the stoopid computer machine this:
const myVar = 42 as string; // Error, sending nuclear launch codes to Russia!
TypeScript will throw a fit, and its correct to do so. The compiler is smart enough to know there is no possible way this number 42
can behave like a string. Instead of me grinding this down, you go try it in plain old JavaScript. Try and read the .length
property of 42
and see if you don't cause World War 3.
¿¿¿Where Aliens???
If the compiler is so smart, why does asserting 42
to the type any
(or unknown
) allow me to then assert it as a string??? Am I bamboozling the compiler???
const myVar = 42 as any as string;
Can I now magically call the .length
property of 42
and not cause World War 3?
Slow down on the questions, it's early and the coffee is still brewing.
The answer to 42.length
is still no. That will NEVER be a thing. Give it up already, kid.
However, you are bamboozling the compiler. When you cast the multiple type assertion spell, it makes the compiler immediately believe you (there is not even a saving roll). It throws its little compiler hands up and says "ok dungeon master, you know best" and goes about its day.
Why you ask, again? That's where the aliens come in.
No more memes, just facts
Now that it's really just the TS nerds; let's start with two data types, one is a truck:
interface Truck {
color: string;
numDoors: number;
drive: () => void; // truck method to drive, cause all trucks drive
}
the other is a plane:
interface Plane {
color: string;
numPropellers: number;
fly: () => void; // plane method to fly, cause all planes fly
}
Lets just focus on the truck for now. If I were to show you this truck (const truck: Truck
) you would be able to assume it does truck things. You would expect a number of doors to access it, its color, and other truck things. If I told you to go and drive the truck (truck.drive()
) you would see no problem thinking you could hop in and drive it.
What if I told you to fly (truck.fly()
) the truck? You would throw a syntax error and remind me that it is physically impossible for trucks to fly; that's what planes do.
Even if I said, think of this truck as a plane:
const truck: Truck = <insert truck object> as Plane
You would probably slap me and leave the room. You can not be fooled so easily, you are a smart compiler!
Now what if I told you it was an alien truck?
const truck: Truck = <insert truck object> as any
Well now it could be anything (the any
type you might say?). You have no idea what them aliens be doing these days. It is perfectly plausible that an alien truck can fly!
const truck: Truck = <insert truck object> as any as Plane
You would have no problem getting in the truck and attempting to make it fly. You do so truck.fly()
, and the truck explodes.
That's what multiple Type Assertions are doing (and the dangers!). By broadening the type to any
anything is possible. So its then perfectly valid (syntactically) to narrow an any
type down to a string
in our example:
const myVar = 42 as any as string;
BUT WHAT ABOUT 42.length
??
You would be correct in worrying about this. Since the compiler does not care, you could run this code. In code the "alien" veil will come off revealing a regular old truck trying to fly, when it can't. Then the program crashes just as the truck would.
However, there is a correct way to do this. Instead of going to aliens for a flying truck, you could just invent it like the genius you are!
In TypeScript you can extend interfaces to add functionality to them, so to make your special truck you would simply:
interface FlyingTruck extends Truck {
// You will get all the properties of the Truck type
fly: () => void // Plus the ability to fly!
}
And Presto! You have now invented the flying truck. When you then instantiate a FlyingTruck
object you will be able to fly that bad boy without any issue. The compiler is happy, the JavaScript interpreter is happy, Giorgio A. Tsoukalos is happy, and you know what? I'm happy.
Felt clever, might delete later
If you liked this article (or just love TypeScript as much as I do) let's talk about it! In the comments, though, to drive engagement on the post ;)
Posted on December 4, 2022
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.
Related
August 16, 2024