Conversion to TypeScript: Lessons Learned from an OSS Maintainer
A Formidable engineer recently undertook the conversion of his long-maintained OSS package to TypeScript. React-swipeable has been around since 2014 and provides a straightforward interface for tracking "swipe" user interactions.
An example use case would be an image carousel that you can swipe to the next image —swipeable will tell the developer when and in what direction the user swiped.
The TypeScript conversion was a part of a recent major version release, v6.0.0
A few fellow engineers and our Director of OSS decided to ask colleague Emil Hartz a few questions related to his TypeScript conversion to share learnings for others considering a similar undertaking.
Why convert to TypeScript?
I have been working within TypeScript professionally for over a year and a half. While mostly an enjoyable experience, some days feel like all you've done was battle with types. Overall, though, the confidence gained and the increased development speed feel worth it.
List of reasons that helped persuade me to convert:
-
JavaScript communities at large have started to amass consensus around TypeScript
-
Can help communicate and document APIs effectively
-
IDEs can now parse and display package APIs even when not using TypeScript
-
Converting definitely increased the barrier of entry for new OSS contributions
-
Allows swipeable to remove
proptypes
as a dependency, which reduces bundle size -
Swipeable's already-exported types will now be used internally so they'll stay up to date
How difficult was it?
Overall I'd rate difficulty as a 5/10.
React-swipeable doesn't have a lot of complex internal workings that require intricately constructed types. The majority of the conversion difficulty was around arduously analyzing and fixing each individual TS error line by line. Additionally, there was overhead in marshaling all the different TypeScript tsconfig
files needed to support the core, tests, and examples.
What were the most painful parts?
I'd say the most painful part was upgrading all the dependencies. This is because I hadn't kept these up to date, making the conversion harder than it needed to be. Dealing with dependency issues atop introducing TypeScript was a bit of a headache trying to get everything to work together.
We ended up creating FOUR tsconfig
files to handle the core, tests, and examples. We can probably align these down the road, but to get the conversion finished, separate configs really helped.
Do you have hints to offer someone thinking of doing the same?
- Yes, stay on top of upgrading all your dependencies regularly! Get everything else up to date and in order before starting to convert (Webpack/Babel/Jest/react-testing-library).
- Perform the conversion in steps or chunks if you can. One big conversion can be daunting and exhausting.
What should someone know before they start?
The process will take more time than you think. Isn't this the answer to most undertakings in life?
There will be unknowns, roadblocks, and trap doors awaiting you. TypeScript and JavaScript are ever-evolving and improving. There is no right time to convert or even start with TypeScript.
Make sure you try to have a general plan or outline how you'd like to tackle a conversion.
For example:
- Convert pure util files and methods first
- Then convert the "core" of the package
- Finally convert the tests to TypeScript too
Do you need to be a TypeScript expert to undertake a conversion?
You do not need to be a TypeScript expert. I am in no way an expert with TypeScript—I've only been working with it for over a year.
You can absolutely be an enthusiastic beginner as there are a massive amount of resources at your disposal, including an amazing TypeScript playground were you can set up examples and share them to ask questions and seek advice.
What do you wish you'd known sooner?
To avoid tests that relied too heavily on implementation details. I wish we'd had refactored react-swipeable's tests to react-testing-library a long time ago.
This is related to the TypeScript conversion because the previous tests partially relied on internal knowledge of swipeable. When we refactored the tests to focus on the interface and functionality, they, in turn, gave us confidence during and after the TypeScript conversion.
What downsides or drawbacks do you see from converting to Typescript?
Converting definitely increased the barrier of entry for new OSS contributions.
Not everyone is on board with, or even using TypeScript, so requiring contributors to know TypeScript in order to contribute now limits the people who can and are willing to contribute.
This downside was probably the hardest to cope with personally, especially since this project was the reason I started contributing to OSS and if it had been written in, say, CoffeeScript (which was popular at the time), I probably wouldn't have felt like contributing.
But on the bright side and looking towards the future, TypeScript has strong backing from Microsoft, great documentation, an incredibly helpful and driven community, and the fact that all valid JavaScript is also TypeScript code, so swipeable being written in TypesScript doesn't necessarily mean someone that only knows JavaScript can't contribute.
Would you recommend undertaking a conversion to TypeScript to someone else?
Yes, specifically packages similar in size and scope to react-swipeable I feel are great candidates for conversion.
Packages that are building blocks used in the construction of bigger, more complex components and features can benefit greatly by having a solid core with a strongly typed API and user interfaces.
But outside of that, I would probably not recommend converting, and I think this response falls along a similar vein across our industry. Either start with TypeScript or not, but avoid converting in general.
Do you think it was worth the effort?
Overall react-swipeable gained some amazing benefits from converting:
- Allowed us to remove the
prop-types
dependency, which reduced swipeable's bundle size by ~35%! - Helped solidify and document the API, as well as provide confidence in the accuracy of exported types, as they are the same types used internally.
At a personal level, I don't know if I would have tackled this conversion if I didn't have access to the amazing resources here at Formidable including our Sauce Hours and Open Source maintainer hours. Thank you, Formidable, for prioritizing and allocating time for OSS contributions!
In Closing
If you're interested in the code, the majority of conversion was in PR 188, which was a part of the v6.0.0
major release.
Takeaway #1: Keep all your dependencies up to date—your future self and others will thank you.
Takeaway #2: Try to start with TypeScript if you're interested and avoid large TypeScript conversions for your own sanity.
Takeaway #3: Tests that focus on validating functionality and not implementation can give you confidence when undertaking major refactors like converting to TypeScript.