Why TypeScript is the best way to write Front-end in 2019–2020+
TypeScript is getting more and more popular in the Front-end environment. Already 80% of developers admit they would like to use or learn TypeScript in their next project. Myself, I have loved it since I used it for the first time. And I will continue using this in all my next projects for sure.
Some people raise concerns that TypeScript is an unnecessary dependency of the front-end toolchain. Is it? Follow me in order to learn that the reality is quite the opposite.
A story of a “dynamically typed languages guy”
For the most of 18 years of my programming career I had never liked statically typed languages. Since I started out with programming in 2001, my languages of choice were always dynamically typed: PHP, JS, Ruby, Elixir. I had done some programs in C++ and Java here and there, but I always hated those environments. (“Why do I need to pass the type everywhere? That sucks. I can take care about them myself.”)
Everything changed about 2 years ago. It was when I used TypeScript for the first time. However, I hadn’t fell in love with it from the beginning. In the first few days it was actually annoying me. Situation changed quickly though. The more type definitions I was putting into the code, the more often I was noticing that it was saving me from wasting time on manually debugging stupid bugs in the console. I was starting to appreciate the types.
In the next two years, whenever I was collaborating on front-end applications, whether it was Angular or React, I noticed that no matter what framework I was using, there was always this one thing that I missed in all .js projects: TypeScript.
Now I have to admit. I don’t like dynamically typed languages anymore. I can still work very effectively in them, but it makes me unhappy when I can’t just look up type definitions in the IDE, or trust the compiler while prototyping the code. (The only thing I still miss in Elixir are strong types.)
Nevertheless, some still dare to argue that bringing TypeScript to your project will:
- increase the duration of on-boarding new developers,
- complicate maintenance,
- introduce a lot of conflicts with React,
- increase development time,
- lock-in the project to some hipstery tech that won’t exist in a year from now,
- prevent recruiting good JS people,
- make it impossible to bring code from non-TS codebases,
- make it difficult to edit the app in the distant future.
I dare to say they’re all wrong. TypeScript will help you with all of the above cases, and I can give you specific arguments why is that so.
That is why I decided to write this article. Maybe it will help convincing you, your friends, workmates, or your CTO, to this awesome language.
Note: I won’t be explaining “what TypeScript is” in this article. I’ll focus only on “why” you should be using it. If you’re still unfamiliar with what TypeScript really is, I suggest you reading some of the following links first:
1. Code easier to understand
Usually when you work on a piece of code, for example a function code, to understand it fully you need to grasp:
- What arguments does it accept?
- What value does it return?
- What external data does it require?
- What does it do with these arguments and external data in order to produce the return value?
In dynamically typed languages, very often it is difficult to answer the first three questions. If a function receives
article argument, what exactly is it? Is it an object with some article attributes? What exact attributes are there? Is there an
article.name ? Can I always assume that
article.title exists? How about
article.isPublished? I might know that this attribute is merged into the
article object in most of the places of the app, but can I be sure, that it is always present in this spot as well?
To answer all of those questions, usually you’d need to do one of the following:
a) put a
console.log(article), run the script in your browser, (maybe click through the UI a bit), and read the log;
b) see where the function is used and from there track down what data is put into all of its occurrences;
c) ask your colleague that recently had been working on this code (while hoping that they are still alive, online, and remember that code);
d) assume that
article is like what you think it is, and just hope it works.
Does that sound familiar to you?
To me, that sounds like a typical web dev workflow in any dynamically typed language like JS, PHP, Ruby, Python, Elixir.
In statically typed languages like TypeScript, you get answers to all of the above questions immediately from your IDE and compiler. No longer you need to look through entire code base, keep bugging your workmates with questions, or risk having bugs on production.
2. Code easier and faster to implement
Typically, when you have to create a new feature or a new component, your workflow probably looks something like this:
- Bootstrap the component function, make up its constructor arguments, write the remaining code.
- If it requires any external or sophisticated data (like
articles), guess how will it look like, keep it in your own memory and use it like that in the code.
- Put the component into your app and pass props into it.
- Test it, either manually or with unit tests. (You need to make sure that it receives the props it should have and that it works how it should work.)
- If something isn’t right, go back to your code, try figuring out what’s wrong with it, fix it, and go back to step no. 4.
In TypeScript, it is similar, but easier and quicker:
- Bootstrap the component function, define its’ type definition, and implement it.
- If it requires any external or sophisticated data, look up their interfaces and reuse them (fully or partially).
- Put the component into your app and pass props into it.
- That’s it. (If you matched the typedefs correctly between the caller and the callee, everything should work flawlessly. The only thing you have to test now is the actual business logic of your component.)
Thus, whenever you write code in TypeScript, not only it is more readable and less error-prone, but mainly, just easier to reason about.
3. Code easier to refactor
There’s often quite a lot of things you’d like to refactor, but because they touch so many things and files, you’re just too afraid of changing them.
In TypeScript, such things can often be refactored with just one click of “Rename Symbol” command in your IDE.
In dynamically typed languages, the best thing you can get to help you with refactoring multiple files at the same time is Search & Replace with RegExp.
In statically typed languages, Search & Replace isn’t that needed anymore. With IDE commands like “Find All Occurrences” and “Rename Symbol”, you can see all occurrences in the app of the given function, class, or property of an object interface.
Whenever you want to improve your build system a bit, rename your components, change your
user object, or remove a deprecated attribute, you don’t need to be afraid of breaking things anymore. TypeScript will help you finding all the usages of the refactored bit, renaming it, and alerting you with a compile error in case your code has any type mismatches after the refactor.
4. Less bugs
Throughout many years of front-end web development, I have noticed that I could save up around ~50% of my time in bug fixing just by having somebody sitting next to me that would immediately yell at me whenever I was doing a typo, using a value that might be null, or passing an object into a place where it should be an array instead.
I’m happy to say that I finally met that buddy: it is called TypeScript.
Thanks to it, it is now way more difficult to write invalid code. If it compiles, you might be quite sure that it actually works.
5. Less boilerplate tests
When you are sure your variables are passed correctly into all given places, you don’t need to test all of it that much anymore.
Instead of writing simple boilerplate unit/integration tests, you can focus more on testing business logic of your app, instead of testing whether your function arguments are being passed between each other correctly.
Less tests means shorter time to develop new features, and a smaller codebase, which in turn is less complicated, less error-prone and easier to maintain.
6. Code easier to merge
New junior developer in your team has just issued a PR introducing new code. At a first glance it all looks o’right: the code looks good, the unit tests are there, everything passes green.
Can you be sure at this moment that it works though? What if it doesn’t have proper unit tests? (Yeh. Let’s meet the reality folks, a lot of us still don’t write sufficient number of them.) Will you just trust the PR creator? Or will you focus your precious 5 min to actually run the code on your own and test it?
If you have TypeScript in your toolchain, it gives you another assurance check: the typedef compilation check.
If the code looks good, the unit tests are there, and the whole thing compiles, now you can be pretty sure, that the whole thing works.
TypeScript makes it easier to trust other developers. It might improve the pace with which you review and merge PRs.
(The same goes the other way: thanks to type definitions, for new developers it is easier to see what other people’s portions of code are really doing, without the need of deep diving into it or running it by themselves.)
7. Aids the developer in having the correct workflow
When writing code in statically typed languages, you first need to think about the types of the data you’ll receive, and then about the type of data you want to produce. Usually only after that you sit down to the actual implementation.
Many people will bet their life that this is the correct coding workflow.
For example, whenever you develop an algorithm, you should first think about its’ theoretical formula, and then implement it.
Or, whenever you do TDD, you first need to think how your code will work in reality (what data will it receive and what data will it produce), write it as tests, and then implement the actual code.
Same thing applies to TypeScript. It encourages you to think about the interface of your code before sitting down to its’ internal implementation.
1. “It will harm our recruitment”
Regular JS surveys clearly show that more and more people are both programming in TS or willing to try it.
The above survey proves it: as of 2018, 80% of front-end developers would like to work in TypeScript.
Having TypeScript in your stack probably won’t harm your recruitment. It might actually do the opposite. If a developer sees that you use the best tools available on the market, he will be more willing to work in your company. Modern tools bring modern developers.
2. “On-boarding will take more time”
On the contrary though, if you have an already built project in TypeScript, it will be super easy for new developers to fit in. TS Syntax is intuitive and very easy to understand (which probably is the reason why it has gotten so popular). Generic function interfaces, type guards, conditional types? You’ll never have to touch nor understand those in 99% of your daily work. The remaining 1% is usually something that has to be done only in the beginning, which can be prepared by an already fluent TS programmer.
Moreover, thanks to TS advantages (which I mentioned earlier on), it will be easier for a new developer to start doing things in your existing codebase. If he only needs to change a small thing or implement something new, he doesn’t need to browse through entire codebase anymore to understand what data is passed and where. He can read it instantly in his IDE and play around with the data. The TS compiler will give him instant feedback about the variables he uses and will guide him whenever he makes any mistake.
3. “React/Redux and TS doesn’t suit each other”
False. TS has had TSX support since long. Also thanks to simple generic types like
React.Component<Props, State>, you can get rid of PropTypes and use real type system instead.
It is true that about a year ago it was required to write a bit of boilerplate code to make TypeScript work with Redux action creators. But since TS 2.8 has been released in February 2018, this is no longer a case. You can have both typed and simple React/Redux code in TypeScript. FYI, React Contexts or Hooks work flawlessly with TypeScript.
4. “It will be impossible to reuse JS code in a TS app”
Again, false. Any JS code is a valid TS code.
It is true, that if you use TS in strict mode (
noImplicitAny), you’ll have to add some types here and there to make the JS code work. But that’s it! There is even an IDE plugin that can automatically convert your JS React components directly to TS.
When you need to copy some weird old vendor js lib to your TS project: just do it. If there are no TS typings for it (which happens less and less often now), add them yourself or just use
any when referencing the vendor. It’s not like suddenly you’ll lose type safety in your whole app. You’ll lose it only in the layer that touches the untyped vendor. But that doesn’t prevent from easily typing your layer at least. And for the vendor, you can always add the typedefs for it later on, whenever you decide they’d be helpful as well.
5. “By choosing TypeScript, we might end up being locked with some legacy tool, that nobody will support in the future”
TypeScript is at the moment used by Microsoft, Asana, Lyft, Slack, all Angular 2+ developers, multiple React & Vue.js developers, and thousands of other companies. Many others are joining them every day. TypeScript is the most popular superset of JS at the moment and is not going down anytime soon.
What is the chance that such language will be abandoned?
I’d say close to zero. The only scenario in which TS could die is if JS would bring in types to their language on their own. But this won’t happen anytime soon for sure. At least not in the next ~5–10 years. In the rare case that would actually happen, you can be sure that there also would be tools that would let you easily migrate from TS to typed JS.
~5–10 years from now might be a time in which nobody knows React, Vue nor Angular anymore. But you don’t see a problem with sticking to those frameworks I guess? ;)
6. “What about Flow?”
TypeScript gives you the same thing that Flow does, and more. It is also way more popular.
Just this should be already enough for you not to consider Flow at all. If it’s the same thing, but with less functionality and much smaller community support, why would you consider it?
In hindsight, Flow used to be as popular as TS about ~3 years ago, when both of them were fresh players on the market. One of them was being pushed by Microsoft and Angular community, while the other was preferred by Facebook and some of the React community.
TypeScript eventually won. Nowadays more and more developers from all the front-end frameworks are switching to TypeScript.
There’s also a few other typed-JS alternatives out there (like PureScript or Elm), but let’s not consider them here. I want to talk about something that has wide community support and multiple companies already using it in production, not just a few hobbyists. (Sorry, folks.)
1. Requires a compilation step
Some of my back-end Node.js friends told me that introducing TS for them is just not worth it, because it would bring a lot of hassle with the need of precompiling all of the
.ts files before running them on Node.
While it is something that for sure you can handle with good build and development setup, I can’t disagree that it adds a bit of overhead to your Node.js application.
I can’t agree on this in Front-end environment though. Everybody compiles JS in the front-end nowadays. You need legacy browser support? ES7 features? CSS-in-JS? For all of these you probably already use babel. TypeScript can be compiled with Babel, just like any other syntax of JS (including ES7 or JSX).
Bringing TypeScript to your front-end project brings almost no overhead to the build setup. (It may bring overhead only in cases when you don’t compile your JS at all, but that happens in the front-end very rarely.)
2. A bit difficult to set up
I can agree on that. For example, what is the difference between a Next.js app and a Next.js app in TypeScript? In the second case, you need to make your Node.js server, webpack, and jest test runner to work with TypeScript. Also, whenever you add some library like React, Redux, Styled-Components, you also need to add typedefs for it, like
npm i @types/styled-components (unless the lib has TS typedefs file included in it).
The question you need to answer yourself though, how often do you do such a thing? Is it that much effort, to be worthy to resign from the all of TypeScript advantages?
Am I saying that all of us should suddenly switch to TypeScript? Nope. For example, switching to it in an existing project is definitely a lot of work and it should be strongly thought over before doing so.
However, if you’re creating a new front-end application, which will have to be maintained over time, the case is clear. Go with TypeScript. Honestly, I’m keen to hear what are the reasons against using TS in any of your next front-end projects.
I just want to say this: by using TypeScript you get loads of powerful advantages, for the cost of little extra effort in the beginning.
Let’s do TypeScript folks 😉 💙
“Switching to TS” Case Studios
- “TypeScript at Lyft” — Mohsen Azimi, Medium
- “TypeScript at Slack” — Felix Rieseberg, Medium
- “How we migrated a 200K+ LOC project to TypeScript and survived to tell the story” — Kleo Petrov, Hashnode
- “Converting 600K lines to TypeScript in 72 hours” — Paul Draper & Ryan Stringham, LucidChard TechBlog
Others reviews of TS
- “7 bad excuses of not using TypeScript” — Dmitry Pashkevich, Medium
- “Why use TypeScript, good and bad reasons” — Charly Poly, Medium
- “Typescript — Why should one use it?” — Majid, Medium
- “Why TypeScript Is Growing More Popular” — Mary Branscombe, The New Stack