I see your point, but I think that (while not always), it can still be pretty helpful to add your custom types to make invalid states unrepresentable.
This can sound ridiculous on something like C, but if your language has refined types, it's not that bad.
For example, this doesn't look awful to me:
``` type WeirdId = Int Refined (Odd And Less[20587])
val myId: WeirdId = 5 // OK val myInt: Int = myId // Can be used as an Int val myRuntimeId: Either[String, WeirdId] = refineV[Odd And Less[20587]](myId + 2) // Runtime Check val myInvalidId: WeirdId = 6 // Compilation Error ```