Almost two years ago I started a new greenfield project in a small agile team. Microservices, docker, react, redux, all that fancy stuff.
I had some experience with similar front-end technologies, because I had spent the previous year on a pretty big react application written by over 20 front-end developers. It was quite challenging for me. We had a lot of issues back then: problems with models cohesion, growing code base, complex and hard to maintain api’s, inconsistent interfaces, hard to track runtime exceptions.
I decided to find some solution to those issues before starting the new project. I thought that maybe we had problems, because the language itself is a little bit too elastic and forgiving. You can type almost everything and because there is no compilation stage, no constraints and pre-runtime code validation, your bundle might contain severe bugs.
Then I’ve encountered Flowtype and TypeScript. After short evaluation I decided to go with TypeScript and now, after two years, I can tell you – that was a good choice for the project and my career. But if you think that the life of a TypeScript developer is a bed of roses you’d better read on.
In this article I don’t want to elaborate about TypeScripts’ features or dive deep into project setup. There are lots of great resources about that on the Internet (for example official TS documentation: https://www.typescriptlang.org/docs/home.html). It is not an introduction for the beginners either.
It is a story about upsides and downsides of everyday work with TypeScript. I would like to describe my worst experiences with TypeScript and, on the other hand, features I consider the most useful. It’s about pros and cons, tradeoffs and benefits, so let’s start.
First things first – setup
As I mentioned, I had some experience with react and redux, so I wanted to take advantage of that and use similar (custom of course) setup in new project. Usual stuff – webpack, babel, npm scripts, jest, linter. Just one little thing extra – TypeScript support.
If you are in a similar situation right now – I can assure you: it is not just another loader entry in webpack config. I had to provide a dedicated config for TS, replace ESLint with TSLint, integrate the TypeScript loader and babel, plug in TS into Jest (test platform).
Some disappointments came in very fast. TS configuration wasn’t so obvious and “just copy that and test” strategy is not the best way to prepare well performing setup.
You’d better read the documentation carefully before even placing tsconfig.json in your project.
Moreover, there were some issues with Jest (transforms, module mappers) and the css module. Probably you will face them sooner or later. And don’t think, that at least you can abandon babel now – TypeScript won’t provide any polyfills for your new shiny features, won’t transpile your new API’s to code that is understandable by older browsers.
So my advice is – if you can, you should use some starter kit or CLI supporting TS out of the box (like angular cli) to spare yourself that neverending story with a project configuration.
Another pretty unpleasant experience is related with the number of libraries supported by TypeScript.
Personally, I had no problems with missing declarations. Most popular libraries have their own types definitions prepared by authors or community. If there is no such file for a package you use – use another one, there are dozens of packages doing the same thing in NPM registry. You can also prepare “dummy” definition or create real one and contribute to the open source community.
Anyway, there is a much more serious issue – as I mentioned already some declarations are incorrect or outdated. If you face such problem, there is no simple solution. You could either stay with an older version of the package with a working declaration, fix them by yourself and contribute or wait for the authors. Sometimes they react quickly, sometimes they don’t.
By the way, I’m the author of a few simple packages and believe me, even with good will, I used to forget about syncing new features with their types definitions.
There are several basic types in TypeScript and few advanced types and techniques related to them.
Below you can see some basic but really powerfull stuff, for more advanced types please visit documentation: https://www.typescriptlang.org/docs/handbook/advanced-types.html.
Apart from well known types like numbers or strings TypeScript offers also enums.
You can use builtin types like Date or Error. Embrace code tips for faster and safer programming.
If you think that types are “the game changer”, what would you say about interfaces? Interfaces help you write much better code, because they finally allow you to define contracts between objects. I create a lot of interfaces. They are everywhere. Sometimes I have dedicated file, just for interfaces, because they deserve that.
I use them mostly for describing shapes of the objects, classes, functions and arguments. You can share them between modules and treat like real entities in your source code, just remember – there are no interfaces on the runtime, sometimes it is easy to forget about that. That’s why there are cases where it is better to use a class instead of an interface (like with Angular Dependency Injection). Let’s see some real life examples with interfaces:
On the left – incorrect implementation of returning type. On the right – VS Code immediately informs about errors in your code.
On the left – a class incorrectly implements the Driver interface which extends User interface (see previous screen). On the right – descrciptive error information..
Of course there is a lot more new things in TypeScript, like generics (you will use them), enums (meeh, sometimes maybe, for internal things), namespaces, JSX support etc. But you don’t have to know and use them all at the beginning, just play with basic features mentioned above and you will see, that quality of your code will improve.
With TypeScript you can use features like abstract classes. More about abstract classes: https://www.typescriptlang.org/docs/handbook/classes.html
TypeScript supports private, public and protected methods, read only properties. Classes can implement interfaces or extend other classes.
Did I just mentioned code quality? Of course I did, because we all care about code quality (and client needs, and deadlines, and estimates, and…).
So why exactly should you use TypeScript (in a context of code quality)?
- code is free from some very annoying runtime bugs related to typos in names of arguments or variables
- you can establish clear and well known contract between objects
- there are no hacks needed to achieve such things like private members of classes
- there is instant feedback from the compiler, a lot of errors are caught on compilation stage, not on the runtime
- code is easier to read and understand by non-JS developers
- it is much easier to write mocks, stubs and fakes for unit tests, because you know theirs exact interfaces
Moreover, because of excellent IDE support, it is much easier to write maintainable code. Let’s be honest – even when you are working alone on small/medium size application, after few weeks you won’t remember what types of arguments you have to pass to a service or what is the shape of newly created user. You can go to the source, examine the code and extract valuable information (because your code is always clean and fast to read), but wouldn’t it be better to just hover over the function name in your favourite editor and see for example, that it accepts “age”, which is a “number” and returns User instance with “age” and “name” properties?
Oh, at the end I have one more word to say about TypeScript. As always, when you are trying something new there is some learning curve. In the case of TS it is not exactly steep, but steep enough to avoid starting with TypeScript and with a new framework. Especially in large or inexperienced team. That’s why I have chosen that project two years ago for my first TS application – I knew the stack pretty well, so it was a great chance to learn a promising language. I’m pretty sure, that if I had chosen a new framework (let’s say Angular) and a new language at the same time, I would be much more disappointed and frustrated.
Would I recommend TypeScript to you? Of course I would. It is going to help you deliver better code in shorter time. The IDE support is great now, the community is vibrant, the number of libraries with TS definitions is big enough and growing, the programmer experience (fast feedback from compiler) is pleasing. This is the best tool I know for creating modern and scalable web applications (and Node.js services too!). Just bear in mind some cons mentioned above, deal with them and deep dive into colorful world of statically typed languages.