loading...

Learnings from migrating Atlaskit to TypeScript

danieldelcore profile image Daniel Del Core ・4 min read

IMG_1891

This blog is aimed at people who are considering migrating their large projects to TypeScript!

So TypeScript support has recently landed in Atlaskit 🎉 and what a journey it was! I think now is a good time to reflect on what I found worked and what I would do if I was to do it all over again.

Full disclosure: It was a large and challenging undertaking… but one I would encourage regardless!

Our project

In the spirit of transparency, I'd like to share some rough resource numbers, to give you an idea of what you might be in for.

We had roughly ~10 different engineers working on the project over its lifespan. At the start, we had 5 people working on it full-time. This is where we made most of our progress. But as time went on, naturally people were pulled into other, more important initiatives and so about halfway through and we dropped back to 1 to 2 full-time engineers at best, for the remainder of the project. 

It's important to note that we were also juggling other priorities such as support, bugs, other projects, etc.

The whole effort spanned *~6 months all up

Tip #1: Automate everything 🤖

I can't stress this enough, use or build your own automation to do the tedious bits. You'll likely never get something that converts perfectly, but you can get most of the way there.

This worked for us: alexreardon/sink

It automated:

  • Transformed our already type-safe flow code and converted whatever syntax it could into TypeScript
  • It renamed files from .js to .ts.tsx (surprisingly tedious)
  • Added TS specific configuration files
  • Removed old configuration files

Sink is highly Atlaskit specific, but consider taking a similar approach. You wont regret it 😉!

In hindsight I wish we invested more time in automating our conversion. If I was to do it again today, I would definitely investigate an AST based approach.

But still definitely worth the upfront effort!

Tip #2: Do not refactor AND convert to TypeScript 🔥

It is really tempting to refactor code as you go, but you must resist the urge to clean up code while you're migrating at all costs!

When you're migrating you'll look at every line of code critically. You're bound to find things that bother you. But it's important to resist because the risk of introducing a regression is extremely high and there is a strong chance that you or your PR reviewers will miss issues. Think about it, you're touching a lot of files, your PR diff is already cluttered with deltas, and then introducing logic changes on top of that  -  A recipe for disaster🔥. 

Trust me on this one 😅

Just focus on moving from one working state to the next. If you need to refactor your component it should be a separate activity all together. Make a note or Jira ticket somewhere, do it later.

Tip #3: Enable allowJs 🌲

allowjs: Allow JavaScript files to be compiled.

If your codebase is big, do yourself a favor and enable allowJs so you can progressively convert components file-by-file, instead of doing an entire component at a time, which is what we did 😆. I found that it blew-out the size of the PRs and made getting past CI a real pain in the butt 🍑.

Tip #4: Capture the Gotchas 🗒

Keep a list of rules / best practices to govern the team. There are lots of little scenarios that happen over and over such as: 

Which event handler do I use for this prop? How do I type HOCs? When should I use an interface over a type? Should I export my props?

Form these opinions as a team, share resources, discuss together and document it for later use. 

Here are some resources we used…

Absolute god-send: typescript-cheatsheets/react

You might also find these useful:

Tip #5: Go upwards from the leaf nodes 🍂

This should be a no-brainer: Start with the most simple and dependency-free components you have and move up and up the tree until you're finished.

Tip #6: Beware the HOC 🐲

In our conversion the most challenging obstacle to overcome, by far, was successfully typing a HOC (higher order component). Handle these with the most care, because it's possible that the return type of a HOC can be incorrectly typed. 

It's worth noting here that HOCs come in different flavors and the way you approach typing them varies slightly. If you get stuck check out these guides:

Closing thoughts 🙏

Don't let this blog discourage you, it was totally worth every second of the effort in my eyes. We found countless bugs in the process, we learned a lot about the quality of our components and in general feel like we're walking away with an a lot more stable codebase!

Discussion

pic
Editor guide