I tend to agree with you but for problem like this one:
> That you can just do `as unknown as T` is an endless source of pain
You should be using strict typingcheck/linting rules somewhere in your pipeline to make these illegal (or at least carefully scrutinised and documented).
1. If someone is willing to do `as unknown as T`, they're probably also just as willing to do `// @ts-ignore`.
2. It's not only your own code, it's the libraries you use as well. Typings can often be slightly incorrect and you have to work around that occasionally.
Popular libraries tend to get type hygiene issues ironed out rather quickly for 90% of the API surface area. For this reason, i find that lib selection from npm is much easier these days. The heuristic is simple:
1) has types? 2) has (large) download count? 3) has docs?
After that it’s generally smooth sailing. Of course this doesnt at all apply to the application codebase being applied to, but one of the parent/sibling remarks emphasized “madness” and i seek to smooth that over.
For #1, this is literally what PRs are for. Someone might be willing to do it, but it should be stopped before merge. If it isn’t, you have bigger problems to solve than type coercion.
For #2, if it’s open source you’re welcome to change the source or its typings.
You can also turn off all warnings in C and C++ (and C#?). That's not a flaw in the language it's a flaw in code bases and programmers that turn them off.
ESLint rules that require type information (not just stripping types) are prohibitively expensive for larger code bases.
As far as I know, there isn't any kind of tsconfig rule to disallow this (please correct me if I'm missing something here!). So unless you're using tools I don't know about, this is kind of a mandatory last bastion of "any".
You can disallow any, enable the strictest possible null/undefined checks (including noUncheckedIndexedAccess).
And there's also the assertion TS check that normally prevents erroneous type assertions.
But "as unknown as MyType" is not preventable by means of tsc, as far as I know. Unless there's an option I don't know do disable this kind of assertion (or even all assertions).
How large is too large and what counts as prohibitive? We're using lints with types on over a million lines of TypeScript and the lints are instant inside of the editors. They take a good 10 minutes to run in CI across the whole project, but that's shorter than the tests which are running in parallel.
Good point, I was talking about similarly sized code bases, yes.
Because of the hefty CI runtime increase, myself I opposed to adding it. We have lots of parallel branches that people work on and many code reviews every day, where the CI just needs to run from a clean slate so to speak.
But most of the current long CI run penalty in the frontend of that comes from tsc, not ESLint, in my case.
I might look into it again.
In the project there already are all kinds of optimizations (caching to speed up full Ci runs with common isolated parts of a monorepo).
And for TS, project references + incremental builds for development are used, tsc in a monorepo would be miserable without them.
I think it depends on your code and dependencies. At work, the time between making a change in our codebase (which is much smaller than a million LOC) to having ESLint update itself in the IDE can take 5+ seconds, depending on what you changed. But we also use some pretty over-engineered, generic-heavy dependencies across our entire codebase.
> That you can just do `as unknown as T` is an endless source of pain
You should be using strict typingcheck/linting rules somewhere in your pipeline to make these illegal (or at least carefully scrutinised and documented).