TypeScript: Type Declarations vs Type Assertions
What are they about?
In TypeScript there are two ways of assigning a value to a variable and giving it a type:
- Type declaration
- Type assertion
We will talk about what they are and which one is better.
Say we have an interface Person
|
|
We can give the Person
type to a variable by declaring it:
|
|
or by asserting it:
|
|
In the first example we declare that the type is Person
with the statement :Person
and we make sure that the value conforms to its type.
In the second example instead, we perform a type assertion with the statement as Person
. In other words we are telling the type checker that, despite the type of bingo
is inferred, we know better and would like the type to be Person
.
The end results are similar but actually quite different.
Imagine the following scenarios:
|
|
Property name
is missing in type {}
but required in type Person
or
|
|
Type { name: string; email: string; }
is not assignable to type Person
.
On the other hand if we do the same but with type assertion we get different results:
|
|
|
|
As you see, type assertion silences the type checker by asserting that we know better than it does.
How to deal with arrow functions
It is not always clear how to use type declarations with arrow functions.
For example, say we want to map an array of names into an array of Person
.
The first thing we could try is something like the following:
|
|
The problem is that people
will be of type { name: string; }[]
while we want Person[]
.
We might be tempted to assert the returned object:
|
|
Now people
is of type Person[]
as we wanted but all the cons we mentioned earlier.
The best way to deal with arrow function is declaring the return type:
|
|
So, which one should I use?
I hope it is now clear that you should always prefer type declarations because they offer additional safety checks, unless you have a good reason to think you know better than TypeScript.
Typically this happens when a type comes from a context that is unknown to the type checker, for instance the type of a DOM element retrieved via DOM API.
Consider the following example:
|
|
TypeScript doesn’t have a clue of what type of element my-element
could be or whether or not it is supposed to be found because it has no access to the DOM of the page, therefore it infers the type HTMLElement | null
.
But because we do have access to the DOM we have more information and know that it is a button and it won’t be null
so we can safely assert its type.
|
|
The type of button
is now HTMLButtonElement
.
There is also the situation where you don’t know what kind of element my-element
could be but you know it won’t be null
, in these cases you can perform a non-null assertion by using the !
operator:
|
|
and element
will have type HTMLElement
.
Conclusion
Always prefer type declarations : Type
over type assertions as Type
or non-null assertions !
unless you are sure you know something about types that TypeScript does not.