I’ve been programming TypeScript professionally for the last two years. Even with that much TypeScript experience it’s always useful to have a beginner’s mindset.
So it’s no surprise to me that I learned a few things from watching this tutorial video on TypeScript basics. Here are my favorites which somehow never really stuck the last few years.
Tuples are a thing
Array types are pretty straightforward in TypeScript. If you wanted an array of numbers you simply use the type number[]
with your new variable. But what if you knew exactly what kind of array you’re going to use? What if you know the array is of fixed length and of fixed types?
Enter the tuple. In other programming languages, a tuple is defined as a finite sequence of terms. One common tuple we use are enumerations. Enumerations have string variables as their key, and numbers as their value.
In TypeScript, you could describe enumerations as [string, number]
, but they are so common there is an explicit enum
keyword to encapsulate this concept.
A more practical example would be a latitude/longitude combination. Libraries like Google Maps will return a tuple of lat/long numbers. Rather than pull out those values into a number[]
, you know it is specifically a number array of only two values, so [number, number]
would be more appropriate here.
Why does this matter? Because if you have a latLng: number[]
and you push
a 3rd value, TypeScript will not complain. But if you have a latLng: [number, number]
and you push
a 3rd value, TypeScript will complain that your array is no longer a part of your specified type. And since lat/long pairs only come in pairs, you know that 3rd push
was an accident.
Another example would be 3D graphics programming. Every point in 3D space has to fit within the x
, y
, or z
axis. So you could declare type Point3D = [number, number, number]
so that all points in space fit into this tuple (e.g. const startingPoint: 3DPoint = [0,0,0]
).
You probably meant unknown
instead of any
We should avoid any
in our code because that’s TypeScript’s way of throwing its hands in the air and saying “I give up.” To which I would say, “why are you bothering to use TypeScript”?
Now that I know what unknown
is used for, I now look back on every use of any
and now realize it probably could have been replaced with unknown
.
any
says it can be any type: number
, string
, boolean
, object
, Foo
…whatever you want. And it will forever stay that way even if you mutate it.
unknown
, on the other hand, allows for any type because you don’t know what you’re going to get yet but we know we will figure it out later.
The best example I can think of is again the use of external libraries like Google Maps. The chimera of objects you get on the way in may be complex or variable but you know you’re going to coerce some of those objects into numbers for some kind of plotting onto your own map canvas. Because you have knowledge of the future transformation into something defined, unknown
is a better type to use here than any
because it will become a number and won’t change.
If you’re struggling at times to adhere to the noImplicitAny
rule, try working with unknown
before completely giving up on resorting to any
.
never
is great if you plan on throwing errors
Finally, there’s a strange little type in TypeScript called never
. I haven’t used this one yet and it’s because I’ve yet to find a reason to use it…until now.
never
is a type that tells TypeScript “a value will never be returned.” And while JavaScript has no concept of this (and will default to undefined
when nothing is returned) the subtle distinction between nothing returned and never returning is best summarized with error handling.
Let’s say you’re writing some custom error handling functions to purposefully throw
an error and break the app. In this case, you can’t complete the function. It’s not that the return value will be undefined
, it’s that the program stops executing altogether and you never get that far.
You probably won’t be in a situation where you need to only throw an error (i.e. a try
/catch
would be a better pattern) but this type provides this opportunity.
Bonus tip: void
and undefined
are different but you probably won’t use it
As a bonus tip, I wanted to talk a bit more about void
which was a strange keyword to me at first because of the fact that it reminds me of void
in JavaScript which I avoid whenever possible.
Along the lines of never
, void
is a similar type to describe the concept of nothing being returned. JavaScript does have this concept because nothing being returned defaults to undefined
. But if a function can return undefined
, how are these two examples different?
// how are these two different?
const noReturnFn: () => undefined;
const noReturnFn2: () => void;
The answer is that to JavaScript, there is no difference, but to TypeScript, it’s all about if you return
or not.
const noReturnFn: () => undefined = () => {
console.log('This must return');
return;
};
const noReturnFn2: () => void = () => {
console.log('This must not');
};
As you can see, a function return type of undefined
requires that you use the return
keyword while void
does not return anything explicitly.
If we go back to our compiler options we see a suggested code quality option of noImplicitReturns
. If we turn this on then void
becomes a useless type because you are no longer allowed to return nothing; you have to explicitly return something with all of your functions. Now in situations where you would use void
you’ll have to default back to undefined
. Personally, I think this is better because you are being more intentional with your code but now you at least know why void
exists in TypeScript and when you would use it.
Get the FREE UI crash course
Sign up for our newsletter and receive a free UI crash course to help you build beautiful applications without needing a design background. Just enter your email below and you'll get a download link instantly.