At Affinity, we recently finished converting over 100k lines of JavaScript to TypeScript. The conversion took around a year with a relatively low-overhead process, and was totally worth it.

Our strategy was fairly straightforward: first we added types to our core data models, and then we began writing new code in TypeScript. We converted existing code from JavaScript to TypeScript anytime we had to make major changes to it. The remaining files were tackled by volunteers, who migrated one file every two-week sprint.

We learned a lot of small tips on our adventure that would’ve been nice to know before starting, so here’s our top advice for anyone else who’s just getting started.

When converting legacy code, avoid also “fixing” it

When updating code that’s years old, you’re guaranteed to find code that doesn’t do things the “right” way. Stop! Don’t fix it!

Instead, prefer documenting the existing behavior with types (use any if need be), and make a note to fix it in a separate diff.

A lot of “wrong”, “weird”, or “useless” code often does fix at least one hard-to-find edge case and “fixing it” leaves a good chance you’ll introduce some new bug. Forcing yourself not to rewrite things, of course, isn’t a new concept, but I guarantee you’ll get the urge at some point. Fight it.

Having this discipline also has the nice side effect of a cleaner commit history. If, further down the line, some other engineer is debugging code introduced by a fix of yours, it’ll be much easier to see which code actually changed when it’s in a separate commit from the type-adding commit.

When we analyzed a list of user-facing bugs, we found a significant number that resulted from “fixing” things while converting JavaScript to TypeScript. No bugs were introduced from commits that solely added types.

Use Prettier, Use Prettier, Use Prettier

This one is short but important.

TypeScript will make your lines longer and your code harder to format. Don’t insert 30 new rules into your style guide. Even the members of our team with the most reservations about using Prettier quickly came to love it after seeing it in action. Use Prettier!

Create aliases for “any”

When TypeScripting, sometimes you’ll find a type that you’ll need to express as any . This can happen for a variety of reasons: something that’s too complex to figure out in the moment, something that just can’t be expressed in TypeScript, etc.

It can be helpful to declare aliases for any so that you can differentiate the any s that you want to fix eventually from the ones you don’t.

You can start with just a type FIXME_any = any , and as you encounter scenarios that you want to handle differently, introduce other any aliases.

One example of where we used this was our largest, most ancient behemoth of a JavaScript file. By converting it with FIXME_any , we got many benefits of TypeScript immediately, while still being able to slowly go through and incrementally convert it.

Keep your diffs clean

Converting a file to TypeScript often involves a lot of changes as well as a rename. That’s unfortunate, because git tools often have trouble following renames when this happens in the same commit.

We found a solution that works well, involving three separate commits. The first commit just renames the file; the second commit runs prettier (to distinguish formatting vs functionality changes); and the third commit adds the actual types.

A reviewer will then be able to look at each individual commit and it’ll be much easier to verify each set of changes.

Contribute to DefinitelyTyped!

Don’t be afraid to contribute your type declarations or fixes for external libraries to the public type repository, DefinitelyTyped. You’ll get the benefit of the TypeScript community helping to improve your types, and you’ll also help out a ton of other people. Here are some of the contributions we’ve made.

Contributing to DefinitelyTyped is also a great, low-stress launching point into contributing to open source, if that’s something you’re new to and want to get into.

For a high-quality guide to contributing your first types, check out the instructions provided in the DefinitelyTyped README file.