3 basics of TypeScript you probably do not know

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.

A new version of this app is available. Click here to update.