The rise of TypeScript seems to have happened slowly, then all at once (like ketchup coming out of the bottle).
Over the past five years, it has continued to grow in popularity until it is now by far the most liked ”JavaScript flavour”. According to the State of JS 2020 survey, TypeScript is now one of the most used frontend technologies and one with the highest positive opinions.
As I mentioned in my previous post, I was sceptical, but have grown to love TypeScript so that I would recommend it as the default flavour for any new JavaScript project. TypeScript had so many benefits that I hadn’t appreciated before I tried it.
In this post, we’ll take a look at five of those benefits:
- Compile-Time Errors
- Clearer Code
- Tooling Over Documentation
- Safe Refactoring
- Incredible Autocomplete
1. Compile-Time Errors
Let’s get this out of the way first - the obvious benefit to using TypeScript is compile-time errors for type safety.
Did you forget to check if a value is null? Typescript won’t.
Missed a case in a switch statement? Typescript won’t.
Added an argument to a function but overlooked the existing uses of the function? Typescript won’t.
This is generally how people describe TypeScript. It means that, from my experience, when people are hesitant about whether TypeScript is worth the extra effort, this is all they’re thinking about.
Compile-time errors are useful, but it’s the secondary benefits that you get because of the type checking that makes TypeScript really exciting.
2. Clearer Code
TypeScript requires you to be more explicit with your code and with your mental model of how the code works.
It is said that writing forces you to clarify your thinking. It’s so hard to write what’s in your head - attempting to write it down forces you to organise your thoughts, challenge your assumptions, question whether there is a better way. TypeScript is the equivalent of frontend development.
Programming is hard. There are huge amounts of complexity. TypeScript restricts the freedom of JavaScript, but by doing so, it reduces the complexity of the code. This makes it a lot easier to catch bugs and move forward with confidence with what we’re writing.
TypeScript reduces the complexity of the code. That may surprise you. One of the common complaints against TypeScript is how complicated it is. Sure, the basic use cases may be easy, but pretty soon you’re down a rabbit hole with type-generics and conditional types and you’re spending more time reading the TypeScript documentation than actually coding.
When this happens to me, 9 times out of 10 that’s a flag that my code is too complicated. When I think about what I’m trying to do, I can usually simplify my data structures and function signatures. The advanced parts of TypeScript are positive friction, slowing me down enough to question whether there are better ways of designing my app.
“If you find yourself struggling with writing types or you’re basically spending time developing your types instead of developing your app, maybe the code you’re writing is too complicated.” - Ben Ilegbodu
3. Tooling Over Documentation
Documentation is essential for the long-term health of a project. However, it’s also easy to neglect, hard to enforce, and can’t report if it is no longer up-to-date. So if it’s possible, tooling should be prioritised over documentation.
When I started working at a new company, part of my onboarding involved reading the company’s coding style guide. I skimmed through it, but very little stayed in my head. I told myself once I was coding, I would refer back to the style guide to make sure I was following the standards. Unsurprisingly, I never did.
Tools like ESLint and Prettier document your code styles. But they go a step further and enforce those styles while you’re coding. You no longer need to worry about stray console.log
s or inconsistent semi-colons. Instead of the style guide being one extra thing you have to hold in your head, it becomes something you don’t even have to think about. You just focus on what really matters.
TypeScript is a tool that forces you to extract knowledge out of the developer’s head and into the code. It documents what arguments a function is expecting, what shape objects are, and which variables may be undefined. And it will remind you when it is no longer up to date and where exactly you need to update.
Without TypeScript, so much redundant time is spent by each developer having to track down the shapes of objects. It requires searching through documentation and praying they are up-to-date. Or it requires debugging the code and praying your guesses of which fields are required/optional are correct.
TypeScript is an up-front investment that saves you and your team much more time in the future.
“TypeScript shines on a team. Even if the team is you and you-from-6-months-ago” - @swizec
4. Safe Refactoring
I recently had two refactoring experiences that were a world apart.
In the first case, I was updating all our buttons to use our common Button
component. It was a straightforward change, and completely terrifying. The codebase was JavaScript, there were too many buttons to manually check each one and our test coverage was spotty at best. It felt like I was walking on the edge of a cliff, knowing that if I missed or misspelt a prop, that could potentially stop a button from working - a critical bug.
In another refactor, I was changing the shape of the state. Originally we just needed a list of titles but now we needed a title and a description for each item. Fortunately, this time I was working on a TypeScript codebase so I updated the type from string[]
to { description: string; title: string; }[]
and then just let TypeScript tell me exactly what would need updating. It was only halfway through that I suddenly realised how hard this could potentially be in JavaScript. Instead, I hardly needed to think at all.
TypeScript not only gives you confidence that you haven’t missed anything when you refactor but also shows you where you need to update. You no longer need to manually track your variables all over the code - just follow the red squiggles.
5. Incredible Autocomplete
The TypeScript autocomplete unexpectedly has become one of the biggest reasons why I love TypeScript. I imagine it’s one of the reasons why it’s so popular among developers.
Autocomplete means I don’t have to worry about typos (did we name this prop color
or colour
?). I don’t have to keep jumping between files to see which component props I need. I don’t need to keep googling the names of string and array functions.
Let’s say I have a string variable that could be undefined - string | undefined
. I want to see if the string, contains a '#'
character but I can’t remember if I should be using .contains
or .includes
(happens every time!). I enter the variable name, press .
and all the possible string functions are shown to me:
I find the function I want and press tab to select it:
Did you see that? Not only did it help us look up which function we wanted, but it also filled it in for us and used optional chaining to make sure we handle the cases where it’s undefined
. 🤯
All these mean you don’t have to keep interrupting your flow. You can just tab and move on to the next thing. It’s like having a co-pilot as you code.
TypeScript As A Default For New Projects
TypeScript isn’t perfect. There are plenty of arguments against it (some better than others). But for me, TypeScript should be the default for any new project. Instead of asking if there is a good reason to include it, you should be asking if there is a good reason not to.