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).
It does support generics [0].
[0] https://github.com/gcanti/io-ts/blob/master/index.md#generic...