Type Inference
TypeScript can infer (and then check) the type of a variable based on a few simple rules. Because these rules are simple you can train your brain to recognize safe / unsafe code (it happened for me and my teammates quite quickly).
The types flowing is just how I imagine in my brain the flow of type information.
Variable Definition
Types of a variable are inferred by definition.
This is an example of types flowing from right to left.
Function Return Types
The return type is inferred by the return statements e.g. the following function is inferred to return a number
.
This is an example of types flowing bottom out.
Assignment
The type of function parameters / return values can also be inferred by assignment e.g. here we say that foo
is an Adder
, that makes number
the type of a
and b
.
This fact can be demonstrated by the below code which raises an error as you would hope:
This is an example of types flowing from left to right.
The same assignment style type inference works if you create a function for a callback argument. After all an argument -> parameter
is just another form of variable assignment.
Structuring
These simple rules also work in the presence of structuring (object literal creation). For example in the following case the type of foo
is inferred to be {a:number, b:number}
Similarly for arrays:
And of course any nesting:
Destructuring
And of course, they also work with destructuring, both objects:
and arrays:
And if the function parameter can be inferred, so can its destructured properties. For example here we destructure the argument into its a
/b
members.
Type Guards
We have already seen how Type Guards help change and narrow down types (particularly in the case of unions). Type guards are just another form of type inference for a variable in a block.
Warnings
Be careful around parameters
Types do not flow into the function parameters if it cannot be inferred from an assignment. For example in the following case the compiler does not know the type of foo
so it cannot infer the type of a
or b
.
However, if foo
was typed the function parameters type can be inferred (a
,b
are both inferred to be of type number
in the example below).
Be careful around return
Although TypeScript can generally infer the return type of a function, it might not be what you expect. For example here function foo
has a return type of any
.
This is because the return type is impacted by the poor type definition for addOne
(a
is any
so the return of addOne
is any
so the return of foo
is any
).
I find it simplest to always be explicit about function returns. After all, these annotations are a theorem and the function body is the proof.
There are other cases that one can imagine, but the good news is that there is a compiler flag that can help catch such bugs.
noImplicitAny
noImplicitAny
The flag noImplicitAny
instructs the compiler to raise an error if it cannot infer the type of a variable (and therefore can only have it as an implicit any
type). You can then
either say that yes I want it to be of type
any
by explicitly adding an: any
type annotationhelp the compiler out by adding a few more correct annotations.
Last updated