(disclaimer: this is not a "conventional project" web/mobile app / game / whatever. it's basically just a library with one function in it)
(read the technical motivation / writeup at the Notion page, in the links at the bottom)
Background
Atomic CSS promises improved development time and better css bundle sizes and scaling. However, it comes at the tradeoff of lack of type safety. For this reason, I personally tended to shy away from it. Is there a way we can get statically typed atomic css?
What it does
This is a proof of concept for providing static typing into atomic css by introducing strong typing into class combiner function, which are already widely used, both for atomic and traditional css. It does this by using a creator that captures a constraint for arguments to a class combiner which is returned; classes can then be passed to the class combiner for static typechecking via TypeScript errors.
Associated is a proof of concept of its extensibility and ability to handle atomic css frameworks via a validator for the Tailwind CSS grammar, which can then be passed into the creator to produce a class combiner that verifies that every argument is a valid Tailwind class.
How we built it
This project is heavily reliant on having advanced TypeScript knowledge and understanding various aspects of the the TypeScript type system functions, and also leverages the relatively new feature of const type parameters, which has only been on the stable release since 5.0.0 just over a month ago.
To simplify some of the type logic, I used @nomicon/types, a public types library that I work on, which happens to have several functions that proved to be quite useful, particularly the HKT interface.
I manually encoded the entirety of the Tailwind grammar by consulting their docs; unfortunately they don't have an official specification. The associated validator for it again leverages the HKT interface.
Challenges we ran into
There are some weird gotchas with the TypeScript type system, not to mention that programming in TypeScript types isn't exactly the most ergonomic. One thing I still haven't quite figured out is gracefully handling array parameters in the validator-based class combiner, as trying to transform either the validator or the arguments resulted in TypeScript no longer being able to guarantee the "constness" of the arguments and thus provided more general type inference, resulting in weaker typing.
Also, encoding all those Tailwind classes was a nightmare. It felt like a good hundred pages of busy work copying over information, and small nuggets of information scattered across some pages meant automating the work with web scraping didn't feel too viable either.
Accomplishments that we're proud of
I don't think anyone else has done something like this before, so that's pretty interesting :o. Like mentioned above, the project, while relatively short on "actual code", requires quite a bit of knowledge about the TypeScript type system. It's pretty nice to have succeeded (at least mostly) at getting it to work, especially when there is no precedent for it.
What's next for back to class
I'll probably clean it up and publish it under a @nomicon/utils package name or something when it's ready (see also the owonomicon/ts monorepo where it would be stored).
Log in or sign up for Devpost to join the conversation.