How (Not) to Learn TypeScript

Brooks Lybrand


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.

Chapter 1: Tutorial Hell

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.

Chapter 2: How (Not) to Learn TypeScript

In this chapter, I describe how I made a significant dent in my TypeScript learning - through a series of mistakes.

Mistake 1: Trying to convert an existing project to TypeScript

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.

Mistake 2: Resource overload

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,)

Mistake 3: Starting from the bottom

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.

Chapter 3: A Breakthrough!

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.

Breakthrough 1: Learning how to use my resources

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.

Breakthrough 2: Understanding when and when not to use the “any” type

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.

Breakthrough 3: Starting from the top

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.

Breakthrough 4: Learn with others!

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.

How to Learn TypeScript

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:


  • Start with just TypeScript, don’t focus on React immediately
  • Build a simple application or tool
  • Don’t convert a project as your first means of learning
  • If you do decide to convert an app, convert from the top down, not the bottom up
  • Categorize learning materials, and use them appropriately:
    Don’t try to read these all at once, start reading and come back periodically, intermixing reading and learning
  • Survey level:
  • Reference level:
  • Deep dive:
  • My only strong opinion is to set noImplicitAny to true
  • It’s okay to not understand everything in a config file when you’re starting out. From what I can tell, most people just muck around with their tsconfig until they get something they like. As you get better you’ll form stronger opinions—something you don’t need when you’re getting started.
  • Try to avoid using the any type when you’re first learning. Some types will be difficult to think about, but that’s part of the learning process! If something is really complicated, try writing it in a different way.

‍

How to optimize your debugging workflow with BugReplay

BugReplay HQ

We created BugReplay to save you time. Indeed, some of our customers have reduced the amount of time they spend on bug resolution by over 75%– that includes the amount of time it takes to report a bug, diagnose a bug, fix a bug, and test the fix.

 

The “bug report” has made great strides over the last few years. Gone are the days when you would wake up to this: “That thing on the site is broken. Please fix it ASAP.”

 

Today’s post examine's the elements of a good bug report, and how BugReplay can help you at every step. Dare I say- bug reporting can be fun for everyone! Here’s a sample BugReplay bug report so you can see what we're talking about.

 

The elements of a proper bug report include:

 

1.    Title and description. It seems self-evident, but providing your bug report with a suitable title makes your entire team happy. You can keep track of the bugs better, your developers know exactly what they’re getting into without having to open the report, and your project managers can manage the tickets more efficiently. A good title and description help prevent the ticket from getting lost in the shuffle. What’s the problem? And where is it? Keep it short and simple. With BugReplay, you can add a title and description at several points in the process, and edit them later- when you first create the report in the browser extension or later from your dashboard.

 

2.    Steps to Reproduce. What’s the expected behavior? What’s the actual behavior? Start from there. It’s always best to include a note on how to reproduce the bug in question. Include all the relevant URLs! (I don’t want to spoil the fun, butBugReplay captures the URLs– and a LOT of other data– automatically, so you don’t have to. You also don’t have to write out all the steps to reproduce. WithBugReplay, the screen recording captures exactly what happened, and when it happened, allowing the developers to see the bug for themselves.

 

3.    Add some environmental details. Where did you encounter this bug? What operating system? What browser? Was the browser version up to date? Were cookies enabled? Okay, enough questions. None of that matters. Why? Because BugReplay captures all that information automatically.

 

4.    Add the logs.  Developers often want to see your console logs so that they can see what happened. Sometimes they ask for something that you don’t even understand. That often creates friction among technical and non-technical members of the team, or between QA and development generally.BugReplay automatically collects all the frontend data like JavaScript logs, network traffic, and resource timing information, as well as the backend data such as server logs and exceptions. Basically, all the data that you could ever want! And what’s more, all this data is automatically synched with the video, so you can pinpoint what’s happening at a precise moment. You can read more about our full-stack feature set on our Zendesk page. The technical documentation is also on GitHub.

‍

5.    Provide evidence of the bug. If you can capture a screenshot or a video of the bug, then it’ll make it much easier for everyone to get on the same page. Well, the cat’s out of the bag on this one. That’s our core product: all you have to do with BugReplay is open the site, click record, and you’re done. You can also take unlimited screenshots. Here’s the sample bug report again, so you can see exactly what you’d be getting!

 

6.    Send the bug report to the right place. This one is important too. Don’t just send a bug report to the back of the queue. Instead, add the right tags (indicating severity of the bug report) and statuses (frontend or backend, web or mobile, is it design or development, is it in Project X or Project Y, etc.). BugReplay makes all that easy- you can assign the ticket, add tags and status, you can even write some comments in the ticket, or attach additional documents. You can keep the report private or share the report outside your team with a publicURL.

 

7.    Integrate with your existing workflow. To make your life as easy as possible, we’ve also built some integrations, so that you can always make sure the bug report is easy-to-find and given its proper due. We have integrations with Jira, Slack,Trello, Zendesk, GitHub, GitLab, Asana, Basecamp, and Zapier. To sync the server-side data with your BugReplay video bug reports, we have all the documentation you need to set up with our APIs. We also have integrations withSentry and Papertrail, making it easy to incorporate data from third-party vendors. Our Bugsnag integration is in progress.

‍

Speaking of integrations, there’s one more feature we’re excited to write about: automated testing. BugReplay began as a manual, interactive debugging tool. But we’ve now integrated with popular end-to-end automation frameworks to automate the entire BugReplay reporting process. If you’re an automation QA engineer or test engineer or other such position, we have integrations with Webdriver.io, Nightwatch.js, Cypress, and TestCafe. Check out more on our GitHub page. Or watch some tutorials on our YouTube page.

‍

Happy (bug) hunting!

New Add-On: Server Logs and Exception Tracking

BugReplay HQ

Today we’re announcing the release of our Full Stack add-on product, which synchronizes your server logs and exceptions with your BugReplay video bug reports and all the frontend data you’re already collecting.

‍

With the full stack add-on, you can track exceptions whenever you record a bug on your own web application. All network calls towards your backend will automatically receive a special key in the header that your developers can intercept and send back to our API to log whatever is most useful for analyzing bugs.

‍

While you can use our APIs to sync your server-side data, you can also integrate with your existing vendor. We currently offer integrations with Sentry and Papertrail.

‍

You can learn more on our help desk. The technical documentation is also available on our GitHub page. Video tutorials are coming soon!


Converting Create React Apps to esbuild

Brooks Lybrand

As a product developer and not a JavaScript tools expert, I rely heavily on frameworks and packaged tools such as Create React App (CRA) and Next.js to handle the “build” side of my applications. When I leverage these tools to more quickly and efficiently compile and bundle my applications, I rely on someone else having already done the heavy lifting of configuring Babel and webpack.

However, sometimes I want a little more control and speed in my bundling process. That is why I decided to test a new and exciting bundler called esbuild. To do this, I convert a project I’d built with CRA to a custom version that uses esbuild. As an introduction to esbuild, CRA users may find this particularly useful.

What is esbuild?

Esbuild advertises itself as “an extremely fast JavaScript bundler”, which succinctly highlights what this simple, yet powerful tool is all about.


JavaScript bundler

We’ve had JavaScript bundlers for years, long before I became a web developer. You use bundlers to break up your project into multiple files for an easier development experience, while still bundling all of your code together for browsers to run.


Fast

Esbuild’s claim to fame is that it’s fast. This is the driving force behind using it, though there are lots of other cool things it can do (see the “major features” on the first page of the docs).


Why is esbuild so fast? It’s fast because it’s built in Go instead of JavaScript, which is a much faster language. Go also handles concurrent processes really well, making for a speedy bundling experience.

Why use esbuild?

So you can build faster! There are roughly two sides to building an app, development and production.


During development, esbuild uses incremental builds, which make it very easy to change your code, save, and see your updated app. This means you don’t have to rebuild your entire application every time you make a change during development.


Second, there is the production side to building a website. Bundling for production is often different from bundling for development, because you’ll usually want to do things like minify your source code, tree shake your app, and create source maps. You don’t really need to do these things during development, as these features add more time to building your bundle. For small projects that aren’t rebuilt often, the time it takes to build the bundle isn’t that big of a deal. 


However, for larger projects you typically require CI/CD pipelines to catch errors before pushing to production, as well as preview deployments created on every commit. Because of features like these, your production build is generated more often than you’d expect. 


To speed up this process, developers need to get feedback on whether their build passes the test suite, so they can share preview deployments with reviewers more quickly. With it’s incredible speed, esbuild tightens the feedback loop for developers, leading to faster insights and thus new features getting shipped more quickly.

Converting a CRA app to esbuild

To learn how esbuild works, we will convert a simple app which implements John Conway’s Game of Life in React. You can check out a live version of the app, or look at the source code. Note, the application runs pretty smoothly for me on every browser I’ve tried except for Chrome.


Currently this application uses Create React App. We are going to replace CRA with esbuild.

Installing esbuild

We begin the process by installing esbuild and uninstalling react-scripts.



Next we need to update our public/index.html file to fix how CRA handled some images. Since esbuild does not bundle css the same way as CRA, we also need to import all our styles generated by Tailwind CSS in this file. If you’re not familiar with Tailwind, don’t worry about it, just know that it’s been set up to automatically generate build/index.css which has all of the styles we use.



Bundling an application with esbuild

Now we’re ready to bundle our application with esbuild. If we run the following command in the terminal, it will create the production build almost instantly:


npx esbuild src/index.tsx --bundle --minify --outdir=public/build


While we could add this as a script in our package.json file, it is better in the long run to create a JavaScript file to handle the build script. To do this, we create the file scripts/build.js.

‍


‍

We use an IIFE (Immediately Invoked Function Expression) to call esbuild directly, passing in many of the same commands as we passed to the CLI. There is much more you can do with esbuild, but this is a nice start.

Let’s go ahead and update the scripts section in package.json.

‍


Now we run npm run build to make Tailwind create the production stylesheet and esbuild generate the production bundle. If we run npx serve -s public, we can start hosting a local version of the application.

Comparing esbuild and CRA build speeds

If you ran the CRA build before, you’ll notice that esbuild is significantly faster.

I compared running the two side by side and the build time was reduced by 70% using esbuild. The majority of the esbuild version’s runtime is running Tailwind CSS/PostCSS, so the actual work esbuildis doing takes almost no time. This is a really small app, so your mileage will vary, but as your application gets larger, esbuild will scale really well.



Implementing live reloading

We’ve gained some speed, but we’ve lost a big feature, the development version of our application. As a modern web developer, I want to see the changes I make in my code reflect nearly instantly in the browser, which is something CRA gave us for free.\

To get live-reloading setup in esbuild, we’re going to need to do a little bit of work. First, let’s start by installing 2 helpful tools, chokidar and live-server:



Next, we’ll add a start.js file in the scripts directory we created earlier:


‍


There’s a little more going on here, but hopefully the code is pretty easy to follow. Basically we’re using chokidar to watch if we make any changes inside of the src directory, and if we do it will rebuild the application. For more details, take a look at the more fleshed out example from which I derived my script. Now we can run npm start and have our application automatically reload when we make changes to our codebase. Take a look at the code changes we made. It really didn’t take a whole lot to replace CRA with esbuild (especially if you ignore the package-lock.json changes 😉).

What we gained

SPEED!! 💨

I can’t stress speed enough, this is esbuild’s biggest draw. It’s freaking fast!

We also gained a lot of control. Don’t get me wrong, abstracting things away and using pre-existing frameworks and tools to get your apps up and running can be incredibly valuable. But sometimes it’s nice, and even necessary, to look under the hood and be able to hook things up for yourself.

What we lost

We did unfortunately lose a few things. Currently esbuild doesn’t support hot module replacement, so it’s up to you to set up some sort of live reload as we did above. Given esbuild’s incremental builds, this is still very fast.  But we lost some nice developer experience benefits.

Additionally, esbuild does not have a 1.0 version yet. People can and certainly have used esbuild in production settings, however it is still under very active development, so approach with caution when deciding if it’s the right tool for your next project.

Other resources

There are a number of community plugins available which handle things like converting markdown, implementing various css flavors, compiling Svelte or Vue components, and much more. You can create your own plugins if you need, but it’s definitely worth checking out the community plugins first.

Besides the esbuild docs, I found the blog “What is esbuild?” to be a very helpful survey.

If this blog has made you excited about the potential that esbuild unlocks for frontend development, definitely check out Snowpack (a frontend build tool) or Remix (a React framework) which are both amazing and use esbuild. For further inspiration, checkout the thousands of open source projects using esbuild.

Communicating with Developers

Brooks Lybrand

A unique communication challenge

While communication can be difficult in any work arena, communication between developers has unique challenges.

These challenges often center around the nature of the work we’re doing, resulting in asynchronous communication, and issues around how "it works on my machine".

Asynchronous communication

Communication between members of partially or completely remote development teams tends to be asynchronous. Developers communicate with each other across the globe, using a variety of platforms like slack, discord, and email. Frustrations can arise, for example, as developers try to communicate across time zones and potentially even language barriers to resolve development issues with colleagues who aren’t even awake.

“It works on my machine”

Then there is the pesky "it works on my machine" issue. When a developer creates a new feature, it doesn’t always work on a colleague’s - or worse, a customer's - device. This often occurs due to missing or incorrect environment variables such as databases credentials, or differing operating systems and/or browsers.

Trying to discover why someone else's code is not working on your machine can be tough, because you don't know how they got it to work, and what information they need about your machine to debug. Finding a solution in these scenarios requires ongoing back-and-forth communication that potentially becomes very frustrating.

The communication formula

No tool magically fixes communication challenges. Good results come when we cultivate empathy and develop processes to reduce friction. For good developer communication, here’s a simple formula:

  • Assume the best about the other person
  • First understand, then be understood
  • Show your work

Assume the best about the other person

Most people are just trying to do their best and developers really want their code to work for others. Yet it can be easy to become angry when you assume, for example, that another developer is being intentionally vague when your attempt to communicate with them to fix a problem isn’t working.

When communication is difficult, it’s best to take a step back and give the other person the benefit of the doubt. Ask yourself if it is possible that you’re the one not communicating clearly? Perhaps you can fix something too. In any event, choose to believe that others are doing their best to communicate effectively with you.

First understand, then be understood

When reviewing another developer’s work or trying to run their program, ask yourself these questions:

Did you read their instructions carefully? Did you follow each step? Did they leave any comments in their code, or anywhere else that might be useful?

In the best case