It does support generics [0].
[0] https://github.com/gcanti/io-ts/blob/master/index.md#generic...
I think the clamor for runtime type checking in TS is partly because type guards and their benefits could be better explained at the language level, and partly that libraries implementing them effectively are mostly aimed at users who already understand those benefits.
You really don’t want pervasive runtime type checking, except at API boundaries where data is untyped (i.e. the appropriate type is `unknown`). Type guards are exactly designed for that use case. For other cases where the types are well known, runtime type checking is needlessly expensive and redundant.
We just do what you describe now, and don't even really want automated type checking. We just write our own assertion functions. The weakness of writing your own is that you have to sort of "manually" upgrade them when there type changes, or they drift and your editor won't tell you about it.
Not trying to dissuade you from rolling your own, mind you. Heck, it’s been stalled for a while as I focus on other things, but I’m rolling my own whole library (also for reasons, foremost of which is handling JSON Schema generation and validation at runtime without relying on codegen like other solutions do).
But the solution really is to assume `: unknown` at API boundaries and run the values through assertion functions: `isSomeType(x: unknown): asserts x is SomeType`.
After using this sort of pattern, I don't think I would want automatic runtime checks anymore, because creating your own explicitly and calling it explicitly works out not so bad.
Well, until this is released! https://github.com/microsoft/TypeScript/pull/50666
Just a simple function (ensureType) that checks primitive types (angle brackets for min length). You reconstruct the object using ensureType, writing it back into itself. EnsureType returns what is passed in, with the corresponding type. Has worked well.
I wonder how many of us there are ...
I actually googled for this just yesterday!