The JS-to-TS Expedition: Full Migration Showdown or Partial Progress Party?

I write a lot about Typescript. I write a lot about why I think it’s better than Javascript. And perhaps I’ve convinced you too! Maybe you want to start converting some JS projects to TS and see what the fuzz is all about. The only thing blocking you is…

How the hell do I get started?

We’ve all read numerous engineering blogs where the authors can boast they wrote some code or conversion script that they applied to their codebase, for a large conversion. Personally I think this is super cool. However, I’m also aware that these are tailored to their specific use case, effectively making them useless for you and me. Or at the very least uncertain.

So what can we do?

Let’s dive in!

The Two Main Approaches to Typescript Migration

Bit of a bold claim, but I believe there is only two fundamental approaches you get to choose between:

  • An all-at-once “Full migration” where you convert everything to Typescript in one large commit.
  • A bit-by-bit “Partial migration” where you convert everything, sure, but little by little.

Also, I’ve never been one to back down from a ‘prove me wrong’ 😉

Taking the Plunge: Full Typescript Migration

So let’s take a look at how that’s done. Im a full migration, we take a very noble, almost stoic, approach to the conversion ensuring that everything is working 100% as expected when we are done with the migration.

The goal is to reduce overall time spent because we can configure the TS compiler to fit exactly the rules we desire, enabling settings such as strict: true right from the beginning.

This is where conversion scripts can come in handy too, because you understand the rules you define for how you want your Typescript to look, so it’s possible to do it programmatically.

The biggest drawback of this approach of course, is that we don’t see any progress until everything is done.

Slow and Steady: Partial Typescript Migration

With a partial migration the most notable difference will be the use of the allowJS flag in our tsconfig.json.

With this configuration option enabled, we are telling the TS compiler that we still want it to grab all the Javascript files in our specified source folder, and just re-compile it to Javascript, just ensuring we have all necessary files for our codebase to work, in our destination folder.

Typically, with a partial migration things will take much longer because we could have intermittent steps where we have to rely on a lot of any types or similar caveats, that are undesired for our end result.

This is where partial migrations are weaker. They can become a bit weird because when converting just a bit of the time, we usually cannot set as strict compilation rules in tsconfig.json, meaning that is something we’ll have to do at a later point, if those rules are part of our desired end result.

The clear advantage of a partial migration is that you get the ball rolling so much sooner. You can configure an adequate tsconfig.json and get started within an hour, if you’re familiar with the codebase.

Don’t forget tracking!

This is especially true if you’re performing a partial migration. Since everything will go from zero to “good” with a full conversion, perhaps this only applies to a partial migration.

But what do I mean with tracking?

As simple as it sounds, I found it extremely important to keep track of which files you need to revisit to land in the desired state as an end result.
When performing a partial conversion we may need to cut a few corners in order to satisfy the TS compiler as we move along, and we may have dependencies that are not yet converted to TS, making it so we have to take those shortcuts.

To that end it is adamant we have a simple and effective overview of which those files might be.

Thankfully, anything can work!

It could be something as simple as an excel/google sheet, where we just note what type of issue a particular file is experiencing. That could be anything from too many any types, to a //@ts-ignore we had to insert, or something third.

Obviously our IDE will make it simply to know which files have been converted from .js to .ts but it won’t tell us which we need to revisit.

I personally recommend keeping it simple (big fan of the KISS approach) and using google sheets with a filename, type/error, and note columns, so we know enough context to come back and fix things.

So how long does a conversion take?

It could take anywhere from weeks to months, depending on the size of the codebase you’re converting.

It also depends on your chosen strategy, do you do it all at once or bit by bit? As you can tell, they both come with strength and weaknesses.

I personally converted a medium-to-large project which took about 10 months. The process was not a priority and we went with the rule of “when touching a file, convert it to TS while you’re at it”, so a long partial migration.

As you may have seen me mention in other posts, it is wise to recall why we do this. We are software developers, that provide a business value. And at the end of the day we are paid to ship working code. Typescript is a big contributor to making sure things work

With that in mind I think it makes sense to favor a Partial Conversion simply because it gets you started. It provides (some) value, here and now.

Progress over perfection.