Because of this I prefer runtypes [1], because it's much more simple to get my desired behavior. My only gripe is that errors aren't all that descriptive.
I guess I could write a function to pipe/fold into the type, throwing a descriptive error if something fails, but I like the simplicity of runtypes.
Edit: I just discovered io-ts ErrorReporter [2]. That's way better than my solution, and I'm considering switching now!
1: https://github.com/pelotom/runtypes
2: https://github.com/gcanti/io-ts/blob/master/src/ThrowReporte...
But once you have those set up, it's an easy breeze, and the benefits are enormous. Our helper-method with the hopefully self-explanatory name "validateOrThrow<T>(t:TypeGuardForT)" is essentially called at every point where there is some form of incoming external data, and the amount of debugging-headaches that have simply disappeared because of this is mind-blowing.
1: https://github.com/gcanti/io-ts