This article was originally published here.
I know what you may think now. Here we go, yet another article telling us how great TypeScript is. Why do we need to defend a language backed by Microsoft? With typings available for pretty much every popular NPM package out there? And from whom specifically? If we take a look at results of StackOverflow developer surveys for the last three years (2017, 2018, 2019), we can see that TypeScript was always in the four most loved programming languages.
While it's true that TypeScript is very popular and loved by developers all around the world, we still see misconceptions about it every day. Look - it's okay if you find TypeScript off-putting or you just don't need it. I never had to use Python in my workflow and I don't like it, but I see why people would use it. So, why do we need to talk about TypeScript?
TypeScript definitely has it's purpose and the most important ones are;
- Improving communication on the team - JSDoc is helpful, but it isn't that powerful and you need to always check the whole documentation to be sure that information in it is still valid.
- Preventing you from making dumb mistakes - adding numbers and strings, no matter how handy can be sometimes, can cause you a great pain in the long run.
Even if TypeScript had no practical purpose, it still wouldn't be a good reason not to learn it. There are some languages (like Scheme, Haskell or Prolog) which may not get you a job but will definitely expand your horizons and help you to become a better developer. Giving the fact that TypeScript is now used by many companies, there is one more reason to at least try it.
strict setting in our
tsconfig.json like we should do. TypeScript will give us a warning for the method above:
The error above means that we have not explicitly set what type username parameter should have. When type is not set, TypeScript assumes you’d like it’s type to be
any (which basically means it can be anything). Fortunately, strict option prevents us from shooting ourselves in the foot. Why? Because having implicitly set parameters throughout the project is the surest path to a disaster. As our project grows we will forget about these places and we won’t get the benefits of TypeScript’s compiler analysis. Also, it’s pretty obvious by the parameter’s name what data type we would like it to have.
But what about
badges? We certainly don’t want to use them as
booleans but as the objects with their respective properties and methods. For now, we will explicitly define them as
any (even though we’re not required to do so). We will define badges as
any as we know it will return array of some data type. We can also do this for parameters where we’re still not sure what data type they will have. Let’s see our refactored method now.
Now you may ask what makes such a difference between setting something as
any. Well, it’s certainly better to know that something will be array of some things than some thing (which can be array of some things or who knows what else). But let’s say we want to have a method which will check whether user has any badges:
As TypeScript knows that
fetchUserBadges method will return
Promise which when it’s resolved will return
any), it can give us available properties and methods as we’re writing the method:
There is something people don’t quite understand when they compare dynamic typed languages with static / strong typed ones. If you ever followed any programming memes page (please don’t if you care about your health), you have probably noticed some image with comparison of Hello world program in Java (C#, C++ or any other static typed language) and in the Python. People who make images like this would like to prove to us how superior Python is. Sadly, they just ruin Python’s image with such lack of understanding some basic things.
Obviously, writing down types does make you slower than not writing them. But that initial work will make you faster in the long run. This means that:
- Debugging will be easier once your project grows
- Navigating code base will be quicker
- You will catch many bugs before the runtime
- Your code will basically document itself (but this doesn’t mean you don’t have to write documentation)
Many of us probably know about Microsoft’s dark history. But as someone who hated Microsoft with passion (and still don’t have any sympathies towards it), I can say that Microsoft really changed since Satya Nadella took the position of the CEO, at least with their stance towards open source software. If I can list three great things that Microsoft gave us they would be these ones (in no particular order):
- C# – modern language with great support for building safe and robust desktop, server-side and even mobile applications
- Visual Studio Code – probably the best open source code editor on the market today with hundreds of thousands extensions and constant improvements in each version (built with TypeScript)
- TypeScript – do I need to say more?
Saying that TypeScript is bad because it was made by Microsoft is childish at best. We may not like Microsoft’s business strategy but we need to remember that there are thousand of workers in the Microsoft who do their best to build amazing products and TypeScript is definitely one of them.
Another variation of the misconception #2. When people say that TypeScript is hard to read, they often mean that projects they’re trying to contribute to or libraries they’re using are hard to read. This is understandable, considering how complex types can become in a TypeScript codebase.
But guess what? TypeScript is not harder to read than any other strong typed language. It’s about inherent complexity of the project you’re trying to dive in and if you ever worked on production-level apps you know they can grow very quickly. Even in smaller applications type definitions could be long and tedious to read. I remember when I wanted to add types to the
Object.entries method. I ended up writing something like this:
export const typedObjectEntries = Object.entries as ( o: T, ) => Array<[Extract<keyof T, string>, T[keyof T]]>;
And I ended up calling it whenever I was using
Object.entries in the project (and this was before I knew I should import
es2017). I know what it does, it’s well named and there is no reason to make it simpler just because someone will spend a bit more time reading it. If it’s not so obvious what the method does, you can always add documentation for it. Writing unreadable code is bad, but simplifying code where you shouldn’t could be much worse. Einstein has famously said:
Everything should be made as simple as possible, but not simpler than that.
So, when the code looks hard to read, ask yourself a question. Is it possible for me to simplify this without affecting it's intent? Would simplifying this code bring any benefits or it can lead to bigger confusion? Don't think about problems like these through the prism of the programming language. Always try to solve a problem by applying general solutions, and later customize it to follow idioms of the language.
 This doesn't mean you can't find jobs for Haskell or Prolog developers. I think Scheme is used pretty much only on the university, but Clojure is a variant of Lisp which is used more for commercial projects.