JavaScript is complicated and TypeScript needs to be just as sophisticated to meet the challenge. This leads to seemingly many ways to do the same thing in TypeScript, but they all have slightly different reasons for existing. This makes it hard to tell what is the correct tool for the job.
Even for something as simple as typing a closure, there are 3 ways to do so.
Let's say we have a faulty closure and we would like TypeScript to catch our mistakes.
We want a closure that returns an object with a single numeric field answer
. I.E. the type () => { answer: number }
Our faulty implementation will return an object, but be missing the answer
field.
We want to make closure
the type () => { answer: number }
, so our first attempt is type assertions.
We can check the type of closure
and it is indeed what we wanted, but holup TypeScript didn't error. Why didn't TypeScript catch our mistake?
The type assertion const v = x as T
tells TypeScript, "Make v
of type T
if typeof x
can be a T
."
The problem is our faulty implementation is of the type () => object
. TypeScript only checks, "Can a () => object
be a () => { answer: number }
?" Since the answer is yes, there is no error.
Perhaps the more obvious way to type a closure is to use a type annotation.
Great success! TypeScript has caught our mistake, but it is pointing at a type failure with closure
instead of pointing where the mistake was made.
This is because const v: T = x
means, "v
is type T
, error if typeof x
isn't a T
. We have again told TypeScript exactly what to do and has obeyed perfectly.
How we do get TypeScript to point us to the actual mistake? We can use one final form, inferred types.
Finally, TypeScript is precisely pointing to where the mistake was made. But why is this called inferred type when we have a return type annotation? Inferred type here means type for closure
is inferred by the implementation.
When we write, const v = x;
, the type of v
is inferred by typeof x
.
By keeping the type annotation within the implementation, we get our desired outcome that closure
is the type of () => { answer: number }
and allows TypeScript to give us better error messages.
Playground with all the code samples and proof all closures are of the expected type.
Do you want to learn how to write TypeScript that errors well for your fellow humans? You're in luck, Battlefy is hiring.