Typescript is terrible for library developers

August 23, 2022 on Eric Bower's blog

I love typescript as an end-developer. I feel like it dramatically reduces the need to manually write automated tests. It cannot be overstated how much work is involved with writing and maintaining good automated tests so anything that can reduce its utility is a huge boon to productivity.

However, as a library developer, I hate typescript. There are a lot of reasons why typescript sucks for library developers, but at the end of the day it reduces developer productivity. In effect, we are shifting complexity from end-developers to library developers. This places a huge burden on us to be experts with how typescript works.

Documentation

There’s great documentation and blogs for end-developers but there’s very little for library-developers. The closest thing I can find targeting library developers is the section on Type Manipulation.

I think the underlying assumption here is that there is no difference between a library developer and an end-developer, which I reject.

Why are there no guides on the typescript site about library developers? What about a guide on the recommended tools for a library developer?

The kind of hoops I have to jump through to get types “just right” in a web app versus a library is dramatically different. It’s rare in a web app for me to need constructs like conditional types, type operators, and overloads. As a library developer, they are heavily used. These constructs are highly dynamic and embed logic into your types. This leads into my next frustration with typescript which is debugging.

Debugging

How do library developers debug their highly dynamic and heavy use of conditional types, overloads? They bang their head against the keyboard and hope it works. It seems like the only debugging tool available is the typescript compiler itself and expertise. You make a change and see what the end result is for that type. As far as I know there are no better solutions besides having an intuition about how it all works.

The only tool that I know library developers use heavily is the Typescript playground so they can isolate discrete parts of their type logic to figure out why typescript is resolving to a certain type. It also lets you change the typescript version and config easily.

What am I missing here? I’m writing this post not only out of frustration but also because I’m hoping I’ve missed something.

Complexity

I spend a decent amount of time in the redux world so redux-toolkit is a great library to see how types are done correctly in a real codebase. To be clear, they do a fantastic job with types, but the level of complexity is pretty startling:

That is just one example but the codebase is riddled with complex types. Also, when you look around, note the amount of types vs actual code. Purely for demonstration purposes – and ignoring imported code – only ~10% (35/330 LoC) of that file is code that will be transpiled to js.

It’s pretty common in style guides to never nest ternaries. In typescript, that’s the only way to narrow types based on other types. It’s a mess!

Testing

Because types can be generated from other types and the highly dynamic nature of those types, there’s a new class of tests that are required for any serious typescript project: testing your types. It’s not enough to test your types against the latest version of the typescript compiler either, you also need to test against previous versions.

This new class of tests are in their infancy and there’s a barren wasteland of tools that are now deprecated or partially maintained. I’ve used these libraries previously:

There’s a lot of churn in this space and I have projects that are still using deprecated libraries because it’s a huge pain to migrate.

It also seems like there are two recommended tools to use: dtslint and tsd. Why do we need two tools to do roughly the same job? It’s confusing to figure out and frustrating to deal with.

Maintenance

Types add a lot of code to your library. When first attempting to contribute to a project, one must grok the application logic as well as the type logic. This adds mental and code overhead to a project which really sucks. As an example, I help maintain redux-saga, and most of our latest pull requests and issues are specifically related to types.

I spend more time tweaking types than I do writing library code.

I’m proficient with typescript but I’m no expert. It’s frustrating because after spending years writing typescript, I still do not have the necessary knowledge to work with typescript as a library developer. Mastery seems like a prerequisite. Types make it much harder to maintain a js library and especially difficult to contribute to them.

Conclusion

I love typescript and think the team working on it are incredible. Typescript has completely changed the FE landscape and wouldn’t want to dismiss its contributions.

But as a library developer, we need:

I shouldn’t have to read the typescript compiler source code in order to figure out why it’s resolving a piece of my code to a specific type.


Articles from blogs I read

Generated by openring

How to help improve SourceHut's design

SourceHut is a software development forge and it is designed with the software engineer’s needs first and foremost. The design prioritizes things like page speed, minimal distractions, and information-forward layouts. It does not prioritize aesthetics, and p…

via Blogs on Sourcehut October 13, 2022

In praise of ffmpeg

My last “In praise of” article covered qemu, a project founded by Fabrice Bellard, and today I want to take a look at another work by Bellard: ffmpeg. Bellard has a knack for building high-quality software which solves a problem so well that every other solu…

via Drew DeVault's blog October 12, 2022

Site Update: HLS support

Hi blog readers! It's time for a regular update on stuff I've gained expertise in frantically googled and hacked together so I can put it in front of your faces. I use YouTube as a video hosting service because it's largely predictable and it'…

via Xe's Blog October 11, 2022