TypeScript is a superset of JavaScript, meaning it is built on top of JavaScript. Per the documentation, “TypeScript is JavaScript with syntax for types”. This allows you to tell your program and other programmers exactly what type of arguments your functions and classes can accept and return, such as strings, numbers, arrays, objects, etc. This is powerful because it helps avoid a ton of low-hanging bugs (such as trying to access an object’s property that doesn’t exist), as well as document your code as you write it.
That being said, this article is not meant to convince you or motivate you to learn TypeScript. If you are reading this I’m going to assume you’ve at least thought about learning TypeScript, and most likely have made an attempt or two yourself. The purpose of this article is to get you past mere motivation, and instead help you form a plan to learn TypeScript. At the least, I hope you can read my story and have a good chuckle at my bumbling around in TypeScript land.
It took me three tries and nearly one year to learn TypeScript. I started and stopped multiple times, got caught in tutorial hell, and enlisted others to learn and struggle with me. This is my story about How (Not) to Learn TypeScript. And while it may not resonate for everyone, I’m sure there are some people out there who have had the same experiences, or are in the middle of making the same mistakes. This article is for those people.
If you want to skip this tale of trials and tribulations, you can go straight to my take-aways at the end and read How to Learn TypeScript.
It was November 19th, 2019 (insert obligatory pre-pandemic, sweet summer child joke). I was feeling very confident in my JavaScripting, React-building self, and even had a couple of junior developers whom I was mentoring. I decided it was time to take on a new challenge, the challenge that many web developers before me had already faced: TypeScript.
Little did I know how unprepared I was for this endeavour. The only thing I did have in abundance was motivation.
This was good enough for me: a win-win. Whether I ended up liking it, hating it, or was totally indifferent to it, I knew I would find it worth my time to learn TypeScript.
Jump forward 3 months: February 19th, 2020. By now, I’ve admitted to the outside world that I have attempted to learn TypeScript once or twice already, with no success. I tried to blame these failures on not wanting to take up any more of my colleagues' time learning TS. However, I knew perfectly well that this all began as a solo adventure, driven by my own goals and motivations, and thus only I was to blame.
Kristofer’s blog post is a useful one, especially if you feel you lack motivation. Many people try to rely too much on motivation or having the right goal when learning something new. But motivation on its own really isn’t enough. You need a plan, you need a system. I lacked a plan, I thought my motivation to learn was enough, and so I became stuck in tutorial hell, blaming other things for the lack of types in my life.
That is, until one day, I finally did come up with a plan. A bad one, but a plan nonetheless.
In this chapter, I describe how I made a significant dent in my TypeScript learning - through a series of mistakes.
I told you I had a plan. On April 28th, 2020, I decided to convert one of my projects to TypeScript.
As a learning method, converting an existing JS project to TypeScript was a bad idea. This conversion is incredibly deceptive. It seems like it should be easier; you don’t have to think about what you’re coding and can just focus on the typing part, right?
Wrong! Unless your project is split up into a single function per file (which I don’t recommend), you’re going to end up dealing with a ton of errors all coming in at once when you change the extension from .js/.jsx to .ts/.tsx.
I also found that many of my functions weren’t written in a way that was easy to convert to TypeScript. I had arguments that could be multiple types because I was so used to the dynamic nature of JavaScript. I didn’t realize how much code I would end up wanting to rewrite when converting to TypeScript.
What’s more, during the conversion, I was also trying to practice Tailwind CSS and XState. Since I was more familiar with Tailwind and XState, I ended up implementing those two libraries and then stalling on TypeScript. I was doing too many things at once and not focusing on what I really wanted to learn.
My takeaway from all this? If you’re trying to learn TypeScript, focus on TypeScript. Start a fresh TS project, and don’t try too many things all at once.
After two weeks of struggling with the TypeScript portion of my application revamp, I asked a friend for some resources. He was kind enough to send me a “tweet storm” of material he recommended, as well as a few tips and tricks.
Here is a list of all the resources he provided:
These are all fantastic resources, some I’ve relied on more than others. John also provided some helpful tips and code samples in his replies.
However, having these resources did not get me over the learning hump with TypeScript. Not because of the resources, this came 100% down to me. I just didn’t know how to think about the resources in relation to my learning. I didn’t know when to use which resource.
The problem with learning is pretty much never due to a lack of resources, especially when it comes to web development. There are so many amazing and free resources available. To me, effectively learning TypeScript is largely, if not entirely, about the process, and my process for using my resources sucked. I’d go through all the content at a resource’s site before writing any TypeScript. Then I’d get bored and my motivation to learn would start to fade.
(If you’re interested, under How to Learn TypeScript at the end, I’ve included a breakdown of the resources that I wish I’d had while I was learning TypesScript,)
Maybe starting from the bottom works well for Drake, but personally, I wouldn’t recommend it.
That is, if you’re converting a JS project to TS and you start at the “root” of your application versus the “leaves”, this will likely not work out well.
In my case, I started by rewriting App.js to App.tsx, which is the core of my application, or in other words, the “root”. This was a mistake. Lower levels of the application/codebase depend on other components and functions, all of which aren’t typed yet. This means you’re not getting much feedback about your TypeScripting because everything you’re calling doesn’t care what you pass into it.
Additionally, I find that my application “leaves” are usually less complex than core components and functions. This isn’t true for every “leaf” element, but the majority of these functions are simple utilities that do things like convert strings to dates, perform simple mathematical calculations, or generate some straightforward JSX.
The nature of the “leaves” compared to the more core elements makes them much easier to type, and it would have been best to start practicing TypeScript there.
Finally, after three failed attempts to learn TypeScript, I had a breakthrough!
In fact, several breakthroughs, all of which finally allowed me to learn how to use TypeScript.
On August 12th, 2020, I got back to my demo project and finished the conversion.
So what changed? There were a few things.
I mentioned in Mistake 2 that I suffered from resource overload. I think this can often be the root of tutorial hell. I often feel like I have to go through all the materials before I’m ready to start doing any real work. So I get caught up churning through tutorials, yet never cementing the concepts in real life experience.
There are way too many resources you could read or watch which can perpetually stop you from starting. As you finish one resource, a new one is probably being created.
I needed a way to think about my resources. I discovered that it helps to split resources into three categories: survey level, reference level, and deep dive.
Survey level resources are good resources to get a high level grasp of what you’re studying. I found Understanding TypeScript’s type notation by Dr. Axel Rauschmayer to be perfect for this. Additionally, the TypeScript Handbook is also a really great tool. The key for me when reading survey level resources is to stop when I start getting bored. Usually when I start getting bored with a resource, it’s because I don’t have a good way to associate what I’m learning with a problem I’ve faced in the real world.
Reference level resources are pretty self explanatory. I often make the mistake of trying to consume these resources cover to cover like a novel. This generally is not very helpful, and I suffer from the same problem mentioned above: I don’t have a good way to ground what I’m learning in some real life experience. Reference level resources like the React TypeScript Cheatsheets are best used to get you unstuck, or to look at after you’ve solved a problem, to see how someone with more experience approaches things.
Deep dive resources are what you want to use after you have a good foundation. Most of the time I don’t even get into these resources, or at least not until I’ve been using the tool for a while. Certain tools/libraries you’ll use so rarely, or are so simple they don’t need deep dives. In the case of TypeScript, you will likely want to do more deep dive learning as you get better with the language. Everyone learns differently, but for me I find these to be most beneficial after I’ve spent a good amount of time with the language, which can be anywhere from 6 months to 2 years.
This breakthrough is very specific, yet incredibly important when learning TypeScript. Over and over again I heard people give advice to TypeScript beginners and veterans alike, to not be afraid to “slap an any” type on something. The any type is essentially a TS escape hatch. It bails you out of all typechecking errors and helps you avoid having to deal with writing difficult and complex types.
So, when I heard the advice to not be afraid to use any, I thought it would make my life easier to just skip over hard to type functions so they wouldn’t interfere with my progress and learning.
What made things even worse: I seemed to be getting conflicting advice from different engineers:
It sounded like I was supposed to both use any and not use any at the same time. This just left me more frustrated and confused, and made it really hard to figure out what to put in my tsconfig file.
Fortunately, there were a few kind souls on the internet who pointed out that I simply didn’t understand what I’d read.
Implicit (or implied as Iain referred to it) any means that if you don’t provide a type to something like an argument to a function, the TypeScript compiler assumes that its type is any.
I 100% agree that you should avoid this, especially if you’re a beginner learning about TS, since when you add any as the type, you will be consciously opting out of TypeScript. Set noImplicitAny to true in your tsconfig file and let TypeScript start nudging you in the right direction.
I also now better understand the advice from seasoned TS developers about adding any types when writing something complicated. As you gain more skill, this can be a really good workflow when developing your applications. Once I learned how to use TypeScript, I’ve certainly done this myself, but typically I come back and swap out the any type within the same commit or maybe a commit later.
But when you are just starting out with TS, using any can be a very bad idea. There is just too much nuance to when you should add it versus when you should keep trudging along. Plus, most of your learning comes from struggling with the more complex types, even though you’ll be tempted to reach for escape hatches. I encourage you to not use the any type, at least not until you’ve started enjoying the language just a little bit.
On October 7th, 2020, I think I can definitively say that I sort of kind of knew TypeScript.
I have no interest in being a gatekeeper, if you get to this point in any language, library, skill, or hobby, you’re part of the club. If this tweet marks my TypeScript birthday, that means it took roughly 11 months for me to go from motivation to actual learning.
Recognizing the mistakes I’d made, and applying lessons learned from my previous breakthroughs were key to my learning progress.
Another change also made a big difference. Very simply, I just inverted what I was doing in Mistake #3. Instead of working on the ‘’core’’ of the application, I started with the “leaves”. It’s best to start with features that don’t have their own dependencies when you’re converting a project. Even if you’re starting on a new project, it can be best to add the simple things first if possible. Go after the easy wins. It’s okay if you’re not writing the most complicated, interesting types, you’ll get there soon enough. Start making progress and don’t let yourself get overwhelmed trying to think about the whole application.
My final breakthrough: learn with others if you can! While you can learn on your own, learning with others absolutely can make the process more fun and rewarding.
Obviously your ability to learn with others depends on whether you’re working with a community of engineers that includes people who also know or want to learn TypeScript. Even for the solo developers, it’s usually still possible to find some sort of community through sites like twitter or discord.
In my case, at first I didn’t learn with my colleagues because I wanted to make sure we would stick with TypeScript long term. Then it was really helpful and even fun learning alongside other people.
I hope you found my foibles and fumblings in the land of typed TypeScript interesting and helpful. I certainly learned a lot through the process, and I am now very happy to know TypeScript.
To summarize everything I learned, if you came to me today and said you wanted to learn TypeScript, I would tell you to: