I think there are two competing concerns going on here:
- booleans are inherently unclear
- type aliases are sometimes unclear
For the boolean stuff, yeah: use a custom type. I’m on board with that every time. You will almost always get a clearer, safer API. Here’s a whole talk on that: Solving the Boolean Identity Crisis by Jeremy Fairbank.
As for type aliases in general, here are my rules:
-
never use type aliases for simple types like
Int
orBool
. They let you express intent but, crucially, are not checked by the compiler (e.g.RoundUp
andRoundToTens
in your example can be exchanged and will still compile.) -
sometimes use type aliases for types with type parameters so that
Result x a
orDict comparable a
becomeHttpResponse
orStudents
. These have a very low chance of being accidentally swapped in, and the damage is pretty low if they are. That said, I always start with a closed custom type and open it up if necessary instead of the other way around, and has no runtime cost as the compiler will unbox them if it can. - always use type aliases for records. That’s it.