-
Notifications
You must be signed in to change notification settings - Fork 12.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add @ts-ignore-start and @ts-ignore-end directives #47193
Conversation
The TypeScript team hasn't accepted the linked issue #19573. If you can get it accepted, this PR will have a better chance of being reviewed. |
Suppressions are a hack for hacking your way out of issues a cast won't fix (like weird inheritance issues). But a cast will fix almost any issue (even those issues if you're creative with where you cast and to what) - every example you have here can be fixed with a single Honestly, we thought suppressions were a bad idea to begin with and I had to argue they had uses when migrating JS projects to TS (essentially as automatable TODOs since per issue suppressions are easy to place automatically). But some people turn to them rather than the much simpler cast, and seeing the arguments here just reinforces that - suppressions aren't "better" than a cast - they're much much worse, and they leave the compiler in a silent error state where things may not behave as expected. They are an absolute last resort, and honestly the presence of a suppression should itself be an error, to indicate that the project has unchecked code that may have unintended cascading effects on downstream code (like quietly leaking an If anyone is left thinking a suppression like this is their only possible solution, then we've failed in our documentation somewhere - even in JS we support jsdoc casts now, so you can cast out of almost any issues in JS, too. (Even missing imports can be fixed with |
I just tried to use this syntax without know it was a thing, and then I found this PR. So I'd say the syntax is intuitive to say the least. |
Not everything which is intuitive is a good thing. I think that is was weswigham is trying to say. Typescript does not want to give you a bigger gun to shoot yourself in your foot. |
My use-case is a new experimental syntax for EmberJS which uses new syntax that uses in scope variables, but is not traditional javascript since it's transformed during build time (kinda like jsx). So things like imports or variables used in this space are marked as unused, hence grouping all of those and using a group comment to disable "errors". |
There's a conflict from there being two kinds of errors that typically get suppressed: code quality and type checking. Code quality errors are produced by settings like Type errors are different. Ignoring these errors isn't a magic "make my code work" button. Ignoring them can have unintended consequences on how the rest of your code is checked. They should never be ignored unless there's absolutely no other way of getting around the problem (and I've never seen an example of this). There's no valid use case for range suppressions of type checking errors; we should encourage people to fix their types and not ignore errors. This dilemma should be resolved in favour of not adding ranged suppressions. The TSC diagnostics system is basically unconfigurable and it's impossible to ignore specific kinds of errors (which is fine for type checking but less for linting). If you need more control over code quality diagnostics than what TSC provides you can use something like ESLint. |
Then why do we have I do agree suppressions are bad and we shouldn't supress before casts. However.. there's a use case for developers during debugging, migration etc. |
In this example casting to any will lose some of type safety. interface ThirdPartyLib {
/** @param arg can also be an object but not typed */
callFn(foo: { prop1: string; prop1: string; }): void;
} // casting to any
thirdPartyLib.callFn({
prop1: 123, // this is not checked anymore
prop2: 'efg',
// ...
propN: 'xyx'
} as any); // ignore block
thirdPartyLib.callFn({
prop1: 'abc', // these lines are checked now.
prop2: 'efg',
// @ts-ignore-start
// ...
propN: 'xyx'
// @ts-ignore-end
}); I can do some inference gymnastic to do better ( This was fun to hack on and I learned something working on it. It's up to the core team to decide at the end of the day. |
I don't like this either. I don't mind having an open issue for discussion pro and con, but I'm going to close the PR since the compiler code changes all the time and PRs get stale pretty quickly. |
The discussion has been going on for years, I think someone at Microsoft needs to go over the discussion to offer a solution or feedback to the request (there's been enough feedback). It can't be another 4+ years of an open issue. |
I mean, we don't outright decline most feature requests that don't violate the project's guiding principles, so discussions of features we don't really like can stay open, even if we don't currently want to accept the feature. After all, there's always the possibility that some super compelling justification for the feature appears, or that the discussion informs some other feature we create. |
It's showing as closed but I still cannot use
Is there an alternative? |
History and rationale
This is a request from the community for about 3 years now. The most concrete answer that came from the TypeScript is @weswigham's comment in #19573 (comment):
I want us to be more sympathetic with the needs of the community. Casting to
any
might be a great solution but if users don't want to do it they might have a reason for that.foo
being typed with only{prop1: string; prop2: string}
. I can technically cast my argument's type toany
to add more props but that will remove type checking forprop1
andprop2
.any
but take it easier with@ts-ignore
's. Maybe they have processes in place to address comment directives later...@ts-ignore
a few imports. Casting toany
won't work there.I'm sure there are other cases that
@ts-nocheck
or casting toany
won't fit the bill. Let's give the community what it is asking for!A full example
Imagine a library that is wrongly type.
foo
accepts either a string or an object.Also consider that scope of my my work doesn't allow me to change the function signiture. But in my changes I need to pass a large object to
foo
:To get past type errors I have to put in n
@ts-ignore
or@ts-expect-error
directives :This change allows a more gentle way of going around this issue:
Implementation Notes
A
@ts-ignore-start
without a matching@ts-ignore-end
will ignore type-errors up to end of the fileThis made sense to me. Initially I had
@ts-ignore-start
without a matching@ts-ignore-end
being an error like an unnecessary@ts-expect-error
. It was a poor UX because the moment you start using these directives you get errors telling you the first directive you put in is an errorA
@ts-ignore-end
without a matching@ts-ignore-start
is an errorFor obvious reasons. This is probably due to a mistake
Multiple
@ts-ignore-start
is fineLet me know if this should be an error. I feel this is more forgiving and user friendly.
To do
This is still work in progress but I'm open for feedback. While I'm working on these items, please let me know what I should fix!
Fixes #19573