Typescript: Support @ts-ignore for specific errors

Created on 12 Oct 2017  Âˇ  76Comments  Âˇ  Source: microsoft/TypeScript

TypeScript Version: 2.6.0-dev.20171011

Code

function countDown(n: number): void {
    switch (n) {
        // @ts-ignore
        case 1:
            console.log("1");
            // intentional fall through
        case 0:
            console.log("0");
    }
}

Expected behavior:

Ability to make ts-ignore apply to the --noFallthroughCasesInSwitch error but not to other errors.

Actual behavior:

case "1": would also compile.

Revisit Suggestion

Most helpful comment

This would also be very useful for our team, we are slowly migrating a large JS app to TS. We'd like to turn on strict compilation flags (especially --noImplicitAny and --strictNullChecks) but have lots of deviant files that need fixing.

Specific error suppression would allow us to gradually migrate everything to strict compilation.

All 76 comments

Seconding (and wanting to track this)

This would be super helpful in our case as we have a class with a bunch of variables, and a function that accesses them by key value (vs direct getter function). As a result, they are never called directly within the class and are throwing the error despite being necessary to the functionality. I don't want to have to disable the "noUnusedLocals" check across the board, just in the two classes where this is the case.

Edit -
It's been 2 years and a job change, but I wanted to clarify something bc I'm looking back at old issues and realized this description is slightly unhelpful
My use case for this request was more along the lines of this introduced feature
https://github.com/microsoft/TypeScript/pull/33383
But I imagine I did not want to ignore every rule in the file, so wanted to be able to specifically turn off the rule that wasn't preventing working code in an edge case, but we didn't want becoming common practice through the code base

I would also love this, more specifically for the noUnusedLocals rule, we get errors on this:

class NumberEvaluator {
   private expression;
   ...
   public evaluate(){
      this[this.expression.type]();
   }

   private BinaryExpression() {
      ...
   }
   ...
}

Saying that BinaryExpression is not used, but it might be, depeding on the value of this.expression.type. I could make BinaryExpresison public, but I really think it is a private method.

This would also be very useful for our team, we are slowly migrating a large JS app to TS. We'd like to turn on strict compilation flags (especially --noImplicitAny and --strictNullChecks) but have lots of deviant files that need fixing.

Specific error suppression would allow us to gradually migrate everything to strict compilation.

It's actually absurd that this is even still an issue. I've experienced a problem related to this. The underlying cause was due to a typescript change in 2.4, as discussed here:

https://github.com/ag-grid/ag-grid/issues/1708

We were then left with three options
1) pin typescript to some version < 2.4
1) update our code to allow updating ag grid to a compliant version
1) fork our own version of ag-grid until we can upgrade

option 1 is not preferable, as it means we can't leverage any new typescript features and can result in having mismatched dependencies

options 2 and 3 are possible (although difficult), and they really only handle one such specific 'error' preventing successful compilation.

Why is there not an option for us to 'ignore' TS2559 (as an example)?

@stweedie I made pull request with ability to specify error code to ignore, https://github.com/Microsoft/TypeScript/pull/21602 but nothing happens,
@andy-ms What you think about?

@Ristaaf I know it's been a while, but I think your use case (private but only referenced dynamically) could use the @internal decorator, like /** @internal */ BinaryExpression() { ... }. Technically your method is public so tsc won't complain but it doesn't show up in the docs as being part of your API. (I can't seem to find any docs on @internal but I know it's used extensively in Angular...)

Here's another little doozy that I don't believe is covered by any "normal" TS methods. Consider the following:

You're dynamically creating a web worker, i.e. by using an ObjectURL created from a Blob containing the .toString()-ified contents of a function:

const objectUrl = URL.createObjectURL(
  new Blob(
    [`(${
      function() { ... }.toString()
    })()`],
    { type: 'application/javascript' }
  )
);

...and the body of that function contains the single most important thing a web worker can do, postMessage():

// inside worker function
setInterval(() => postMessage('from worker!'), 2000);
                              // ^^^ this causes TS error! 😿

Oh no! TypeScript's implementation of postMessage has a required target parameter in it's function signature. Problem is, we're not using window.postMessage, we're using **self**.postMessage, i.e. the web worker's context! Furthermore, trying to spoof it with a null value makes it worse:

// inside worker function
setInterval(() => postMessage('from worker!', null), 2000);
                              // ^^^ this causes worker exception! ☠️

The web worker postMessage won't accept another parameter! Woe is me.

Since it doesn't make sense to change the [correct] type definition for the window context's interface, and web workers can't use TypeScript [natively], it seems this would be a perfect opportunity to tell the TS compiler "Hey dude, that's a stringified version of some arbitrary _Javascript_ that has nothing to do with you, your execution context even. Back off, get your own sandwich".

@wosevision
Webworker have a special API which is covered by lib.webworker.d.ts
After adding the target Webworker to your tsconfig you should be able to have a fully typed code like this:
setInterval((this: BroadcastChannel) => this.postMessage('from worker!'), 2000);

disclaimer: I never worked with Webworker till now.
For further question opening a stackoverflow question is probably the best.

@HolgerJeromin Thanks, I appreciate the tip. I was aware of the TS webworker lib and target, but this situation is slightly different. The linchpin point is here:

dynamically creating a web worker, i.e. by using an ObjectURL created from a Blob

...That is to say, the target is not a webworker. It's just regular browser JS that happens to be _building_ the webworker. The lib should still reflect the regular lib.dom.d.ts because, for all intents and purposes, we are not inside a webworker and therefore lib.webworker.d.ts typings are useless everywhere else.

It's such an edge case that it would feel silly to do anything other than ignore a line or two.

Is there a reason this issue is still open? I depend on a library that has an incorrect documentation, and it causes unsilencable errors!

See https://github.com/esteban-uo/picasa/issues/27 for more info. This feels a bit silly.

@jlengrand you could use a generic // @ts-ignore comment.
It already works and ignores all TypeScript errors on the next line.
This issue is only about enhancing the feature to enable targeting more specific errors.

Ha nice, I didn't understand that! I saw the ts-ignore issue closed, thinking it had been dismissed. Thanks for the tip!

Without fine control about how legacy files are handled it is really hard to introduce new typescript rules into a project.

Please give this use case some more consideration.

👍

What about a syntax like this:

Ignore all errors (current)

// @ts-ignore -- My reason for this.

Ignore one error

// @ts-ignore:7029 -- My reason for this.

Ignore multiple errors

// @ts-ignore:1248,6133 -- My reason for this.

For #19573, you could use @ts-ignore-start (also with an optional list of error codes) and @ts-ignore-end.

Edit: The -- My reason for this. comments are of course optional (but recommended).

@glen-84 Already implemented pertty like your suggestion in PR https://github.com/Microsoft/TypeScript/pull/21602 They dont`l like to use codes for this purpose. For me, I have forked typescript and just totally remove some errors I like to ignore.

Ah, I vaguely remember this now.

Doesn't seem mutually-exclusive though – they could support both. Codes (for now), and later strings as well.

Who's gonna take the time to pick appropriate names for ~1200 error codes?* 🙂

* Assuming it's here.

It should be fun for errors like:

An unary expression with the '{0}' operator is not allowed in the left-hand side of an exponentiation expression. Consider enclosing the expression in parentheses.

(off topic: pretty sure that should be a unary, not an unary)

The short string code will probably fail to convey enough information, requiring a documentation lookup anyway.

I think a good compromise would be to support numeric codes for all errors, and short strings for simple/common errors like unused-parameter.

@busyrev can you point me to that commit or fork? Id like to do the same..

nice! thank you!

Especially when migrating to TypeScript it is necessary to suppress some of the error messages reported by the TypeScript compiler. Currently TypeScript offers a very rudimentary way to do so and it could be improved by using a syntax similar to lint tools like tslint and eslint by at least offering the following inline options:

  1. disable or enable warnings for specific rules
    //@ts-disable TS1234 TS1235
    //@ts-enable TS1234 TS1235

  2. disable specific rules on a specific line
    //@ts-disable-line TS1234 TS1235

  3. disable specific rules on next line
    //@ts-disable-next-line TS1234 TS1235

Is there intent to make it so that tsignores can be flagged as errors when the following statement has no error to ignore? For example, I'm adding a tsignore to ignore an error that is expected to be fixed in a future version of typescript (#26235), but would like to be reminded to remove that tsignore once typescript is capable of handling it normally

Given discussion on this in the past, it seems like there is a desire to use short text codes instead of integers? Is there anything we can do to iron that out so that some discussion and forward progress could continue? I'm somewhat skeptical of using text since it looks like there are over 1000 possible messages in translation files. With that in mind:

  • Is there a reason that text codes won't devolve into the same level of memorization as numbers (I won't be able to memorize 1000+ text abbreviations)?
  • Is there history on altering of error codes to have the same value previously occupied ones that are no longer in use? If so why vs using an unallocated one, and was there complaints about getting the wrong message for the error code?
  • Is there a persistent maintenance burden on leaving legacy documentation?

I mostly ask because other situations like using rust and node.js don't seem to have problems with static error codes (text or number) even while they are no longer used.

@bmeck I personally have been using numeric error numbers most of my professional career in C and C++ and would not mind them too much. I more recently really started to appreciate the semantic error codes as they are used in eslint and would probably try to use something similar.
Even if the naming of 1000+ error codes might not always be perfect, I see a major advantage in hopefully having a semantic structure based on the different types of errors.
A little off topic but what is absolutely amazing in eslint is how the hierarchical configuration files are handled and I would really hope for something similar in TypeScript and not only the option to ignore specific error codes.

Recently switched from tslint to eslint and I really like the command line option enabling reporting of useless ignore comments as errors (when the given original error to suppress has not occured). I think it is a pretty good solution to no longer used or changed error codes.

I'm also coming from ESLint. I love the way they made their error suppression intuitive to read. Take this example:

if (e.error) alert('Error!'); // eslint-disable-line no-alert

This comment clearly states that for this line only, it's okay to use the alert function. Compare that with an (imaginary) numeric error code:

if (e.error) alert('Error!'); // eslint-disable-line E0815

Unless I learn those error codes by heart (and I'm really bad at memorizing numbers), I'll have no idea what this comment does. Maybe e.error is a private property that I shouldn't normally access. Maybe I've omitted mandatory curly braces. This line may contain any number of problems. Reading the code, I can't really tell what is being disabled here.

@bmeck,

What did you think of my suggestion?:

I think a good compromise would be to support numeric codes for all errors, and short strings for simple/common errors like unused-parameter.

I really don't think that it's practical to have string-based codes for all of the 1000+ errors that may occur, and in many cases they won't even convey enough information anyway.

Your IDE could display the error information when hovering over numeric error codes.

@glen-84 sounds good to me!

More than one year our team using fork with my pull request https://github.com/microsoft/TypeScript/pull/21602 but with additional comment describing what error is ignored here, like this:
//@ts-ignore TS2349 // Cannot invoke an expression whose type lacks a call signature
Using it without comment is really not good when you want to understood what is going on here half a year ago.

I agree with @glen-84 that there may be very specific errors that don't allow for short, memorable string IDs. I like the idea of supporting numeric codes for all errors and string identifiers for a sensible subset.

@glen-84

I think a good compromise would be to support numeric codes for all errors, and short strings for simple/common errors like unused-parameter.

I don't think it helps move this forward if it is considered blocking to have text for error codes. If there is a baseline of all errors having numeric codes, we can start there; then as people desire they can iterate on writing textual strings as errors are considered common/stable enough to keep up to date. I think it should be split to a separate issue as an enhancement.

@DanielSWolf

Unless I learn those error codes by heart (and I'm really bad at memorizing numbers), I'll have no idea what this comment does. Maybe e.error is a private property that I shouldn't normally access. Maybe I've omitted mandatory curly braces. This line may contain any number of problems. Reading the code, I can't really tell what is being disabled here.

Editors have all sorts of hover/code lens/goto enhancements, this would allow more in depth documentation to be linked to in both cases. If your editor cannot support such workflows, uncommenting the line would also reveal the longer error message. People often search for things on the internet when they don't know them, in particular solutions for them and I doubt text based codes would be any different (see ECONNRESET etc.). Unless your codebase is covered with these

Things like @ts-ignore implicit-any are likely to have some usability enhancement, but could just enhance the common error codes rather than preventing this feature entirely from happening. I'd be curious if not having this feature is more valuable than having it both numbers and text (when sensible).

This is curious to me in particular because other language do have error codes that require lookups as I mentioned above and are workable UX. What makes the UX unworkable in this instance/why is this set of codes different?

@bmeck

Editors have all sorts of hover/code lens/goto enhancements, this would allow more in depth documentation to be linked to in both cases. If your editor cannot support such workflows, uncommenting the line would also reveal the longer error message.

I spend quite some time reviewing pull requests on GitLab. Similar to GitHub, their GUI is great for looking at diffs and commenting. But it's no full-blown IDE, so there are no handy tool-tips or interactive compiler messages. More generally, I use a number of tools for working with source code, and I can't always rely on smart IDE features.

This is curious to me in particular because other language do have error codes that require lookups as I mentioned above and are workable UX.

You are right, of course. I've been using Visual Studio for years, and I've made do with their numeric warnings and errors. But I can't say I ever liked it.

Don't get me wrong: I'd be perfectly happy if the first version of this feature only came with a small handful of string identifiers, to be added to later. And if that's too much effort, I'd gladly accept a first version with numeric identifiers only. I'm just saying that if I had the choice, I'd prefer string identifiers.

in the absence of textual codes such as in python, I find it helpful to allow trailing text in the comment so you can add your own description. you can do this today with @ts-ignore

I'd been talking to @orta about what it looks like to have an easier path to strict type checking from a project that has no strict checks enabled. I feel like this feature is a key item that could be added to help us get there.

I'm 👍 for just using error codes. Agree with @DanielSWolf above that you're not always in an environment where you have a rich IDE, but if the TS site exposed a simple url based lookup of error codes (i.e. https://www.typescriptlang.org/error/TS123) then it'd be easy enough to deal with. Short codes for common errors would be nice, but just having _something_ would be better than where we're at.

Looking at the last meeting notes around this topic, I do see the challenges. I feel this comment by @RyanCavanaugh does a good job of conveying one of the largest challenges: Namely error codes go from being just useful for debugging to potentially something that could cause new type errors between versions.

It's a hard problem.

Another potential option would be to provide a customizable error map. I'm not convinced this is the best idea myself, but it's an option...

i.e. in the config

{
  "errorCodeMap": {
    "implicit-any": ["TS123"]
  }
}

then in the code

// @ts-ignore implicit-any
foo(bar) { }

then if something broke between updates you could just update your own short-code mapping. That would at least give people the ability to express intent through the ignore mechanism, though the implicitness of the short-codes and the ignore comment is unfortunate.

This would be great. Here's how I work around the limitation:

        // @ts-ignore: access protected property
        scene._cssLayer
            //
            .removeChild(sceneState.renderer.domElement)

That way, I know that ts-ignore is being applied specifically to the scene._cssLayer access, which is a protected member (it is fine for my library to access "package protected" members). I don't want it to hide any other errors in how I'm using the following removeChild method.

I also use Prettier, so I have to add the extra // comment so that Prettier won't convert

        // @ts-ignore: access protected property
        scene._cssLayer
            .removeChild(sceneState.renderer.domElement)

to

        // @ts-ignore: access protected property
        scene._cssLayer.removeChild(sceneState.renderer.domElement)

so as to avoid unintentionally hiding other errors.

EDIT: I just realized that the following works too, so prettier won't mess the formatting:

        // prettier-ignore
        // @ts-ignore: access protected property
        scene._cssLayer
            .removeChild(sceneState.renderer.domElement)

The ability to ignore particular classes of errors globally (just like you can do in a .eslintrc file) is a must. There is a bit of "squiggly noise" introduced into JS when using checkJS which I would love to disable globally certain issues. checkJS is awesome but that is my only complaint!

@RyanCavanaugh Question for you about your comment here:

The real problem (I'm surprised this didn't make it into the notes) is that we generally don't consider a different error message being issued as a significant breaking change.

For example, we sometimes add a more-specific error message for certain cases to give a better developer experience. Every error message has its own distinct error code.

We don't want people to get into a situation where upgrading from TS X.Y to X.Y+1 yields hundreds of new errors simply because we changed an error message code, or end up doing a bunch of Rube Goldberg work in the checker to issue a "legacy" error message in some cases.

I've run into this problem with error codes in HTTP APIs, and the relatively simple (non Rube Goldberg) solution was: instead of each error having a single code, it has a list of codes. So, if the API originally issues a general error (e.g., type/code: "ValidationError"), and then is later refined to issue something more specific, the new error has the original error's type/code in its list of codes (e.g. ["ValidationError", "PasswordToShortError"]). Then, any program that was checking for the old code will still see the new error as an instance of the old code. Perhaps a similar approach could be taken here?

For backwards compatibility, every TS error might continue to have a primary code, but also a "parent code". New, more-specific errors would be defined with the previous, more-general error as the parent code, and the compiler would continue to always issue the most specific error, without that causing breakages. Only @ts-ignore would make use of the parent codes (ignoring the error if it or one of its parent's has the error code the user asked to ignore).

Perhaps the parentCode field could be named something like "derived from", to get away from the appearance that the error codes form a complete/strict hierarchy (since presumably all existing errors would be left as-is, with no parent code). Or, parentCode could be replaced with an altCodes array in case there are times when multiple previous errors now manifest as one newly-introduced error.

Does this solve the issue with breaking changes?

It doesn't address the case where the error issued in TS vX.Y+1 genuinely new/unrelated to the error issued previously — but, in that case, it's not clear that the @ts-ignore should apply, because TS may truly be catching something you didn't want ignored. My motivation for wanting to ignore specific errors is that I don't want t lose all type checking on a line just because I need to ignore one error (e.g., to work around a TS limitation), so, for that, not ignoring newly-introduced-but-unrelated errors is definitely a win.

--

Re requiring string error names, instead of numeric codes: I don't think that should be a blocker, because a numeric code provides the reviewer with strictly more information than the bare @ts-ignore we have today. At least a reviewer can look up a code from their browser, whereas trying to know what a plain @ts-ignore is for (without a comment) actually requires cloning the code, removing the @ts-ignore, and seeing what the compiler complains about.

I just had a compilation issue in my code where TypeScript incorrectly declared that a property doesn't exist.

ui/controllers/homepage-controller.ts:22:37 - error TS2339: Property 'target' does not exist on type 'Event'.

22         const elementIdName = event.target.href.split("#").pop();

The lines below helped but it'd be nice if I could just disable a specific thing instead of the entire next line.

// @ts-ignore: TS2339, TypeScript is wrong about `href` not existing on `event`
const elementIdName = event.target.href.split("#").pop();

Wibby, your error isn't a good use case for ts-ignore.

The issue tracker here isn't the right place for user support, but the short version is that Event is probably not resolving to the type you think it did. The Hulk-Smash approach is to anycast the variable, like (<any>event).target, but better would be to find out what type TS is actually using for event and fix your type resolution.

If you use an editor that connects to the TS language service (VS Code is very popular) you can just find the line where event is declared and use the "go to definition" command on its type to find the one that's being used. (If you're not explicitly typing event then that's a good place to start.)

My apologies, I wasn't trying to get support for my issue. My aim was to share support for this issue being worked on/resolved.

For my issue I could also just do this:

interface LooseObject {
  [key: string]: any
}

document.querySelectorAll("a[href^='#']").forEach(anchor => {
  anchor.addEventListener("click", (event: LooseObject) => {
    // do stuff
  });
});

I prefer Sublime Text but I'm sure search-engine visitors will find these tips helpful.

Tossing my hat into the ring: I'd really like to ignore TS1206. We have an in-house transformation plugin that's using decorators outside of the currently accepted scope. This is the only instance in which we're violating the sacred rules, but it's super handy for injection in our use case. At present we're having to use the all-encompassing // @ts-ignore and that's no good for catching other issues.

I would love to be able to ignore specific rules especially that crop up as issues with type resolution of discriminated unions, since on version 2.8.3 that I use there happens to be _a lot_ of hits on that.

For something that's been open 2 and a half years, it's hard to tell what's actually blocking this? Is it just that it's not defined well enough? Is there a specific technological limitation? Or is it just the time hasn't been put in (or isn't available)? Just curious, as I too would love this and fully agree that it allows a much simpler path to enabling strict mode.

@vpanta we basically think it's a bad idea. See https://github.com/microsoft/TypeScript/issues/22011

@RyanCavanaugh Then why not close this issue?

Well, people don't like having issues with lots of upvotes closed. We're open to having our minds changed and there's clearly a lot of demand, but need some confidence in a design for the feature that doesn't imply terrible maintenance burdens either for us or TS developers.

Ehh, to me it looks terrible to see a repo with corporate sponsorship have 4k+ issues. I haven't gone through them all but if there is no interest and no work being done on an issue, it doesn't make sense to leave it open. Closed issues can be reopened.

I'm not sure what is necessary to design a (close to) maintenance free implementation of ignoring blocks of code but I do think leaving this "bad idea" open only serves to give false hope of a resolution.

Ryan, the linked meeting notes say "no conclusion yet" -- it sounds like 2 years ago this was discussed briefly then tabled. What exactly is the team "not confident" about? Is the entire problem the fact that //@ts-ignore TS1234 isn't descriptive enough to tell future maintainers what you're suppressing?

If so, I would contend that it makes no sense to hold up the ability to do this at all until you're sure you can hold users' hands enough to force them to document their code properly. I personally go by the rule that if you're turning off any kind of safety check, you'd better explain yourself in the surrounding comments -- any-casts always have a comment explaining why I couldn't do a runtime type guard or write better typings in the first place. Of course users should have a nice beefy explanatory comment by their @ts-ignore already, but do you really need to force them?

It would be most interested in this features and do not fully understand why it should be a bad idea. Clearly changes in the reported errors might require changes in the code using them but at the end it is up to the user of TypeScript if he disables all errors or just a specific one.
On the other hand I currently have to deal with the fact that I repeatedly hat to deal with code that was expected to allow one specific error but ended up hiding other problem in the same line.

One option to solve the problem of not being able to tell what the error code means, would be to have the current description of the error shown as a vscode tooltip when the developer passes the mouse over the error number. Not sure how hard it would be to coordinate this with the vcsode dev folks, but it's an idea.

Just to be clear, the issue here the future-upgrade scenario. Let's say you write something like this in hundreds of places around your codebase:

// @ts-ignore: TS2339, TypeScript is wrong about `href` not existing on `event`
const elementIdName = event.target.href.split("#").pop();

Then we improve the error message to be

 TS7632 Property 'href' exists on 'HTMLAnchorElement' but not 'HTMLElement'. Are you missing a type assertion?
 ^^^^^^

The error code is going to change because there's a 1:1 relationship between error codes and messages. Now what? A routine compiler upgrade that should only introduce a handful of errors is now giving you hundreds of errors with a tedious process for fixing your ignorecomments. That's really bad and we'd like to not paint people into that corner unless we absolutely have to.

You can fix everything with more tooling but at some point the cognitive burden doesn't outweigh the benefits.

A routine compiler upgrade that should only introduce a handful of errors is now giving you hundreds of errors with a tedious process for fixing your ignore comments.

TS can always offer a codemod for upgrades that would take care of this, similar to React. Not ideal, but it's an option.

@RyanCavanaugh If I had hundreds of ts-ignores in my code, I'd definitely want them to have TScodes associated with them, to restrict their error-hiding radius.

But in the few(?) cases where the.TScode kept changing, I might revert to a simple comment to avoid churn.

The situation seems analogous to eslint, where users are already accustomed to updating their ignores as the error types subtly change. Are ts-ignores fundamentally different from eslint-ignores in this regard?

This sounds largely like the need for a perfect solution is preventing a good solution. I can think of multiple responses to your specific argument, but I don't really want to get bogged down in arguing on one specific thing.

Offhand, I've been through multiple migrations where they're much simpler this sort of one-off error squashing. Start with tooling to ignore the current errors so we can move forward writing new error-free code with the codes enabled. Is there a better path to enabling "strict" mode? Or say enabling new error codes in the future?

Probably this feature isn't implemented because of TS team's test process. TS team frequently tests TypeScript using DefinitelyTyped and some projects but if @ts-ignore for specific errors is used in them, TS team has to maintain these @ts-ignore comments. TS team hates this maintenance cost. This would be why @ts-ignore for specific errors isn't implemented.

FYI, I needs @ts-ignore for specific errors to ignore some language bugs in most cases:

https://github.com/falsandtru/spica/search?q=ts-ignore&unscoped_q=ts-ignore

A lot of bugs have still not been fixed. TypeScript hasn't provided any suitable solution to care these bugs.

Would it be possible for the team to ignore ignore comments? 🤔

@RyanCavanaugh I completely understand that there is no perfect solution (as @vpanta called it) but nevertheless I would very much prefer the option to only ignore specific errors.
Like in eslint, a user can still decide if he wants to ignore all errors or just specific ones.
I also believe that there most likely should be a reasonable compromise between completely changing all errors codes in each minor revision and not being able to change them at all.
I believe that by trying to rather add new error codes instead of changing existing ones where possible, trying to combine the breaking changes in error codes to bigger releases and just documenting the changes should very much alleviate this problem.

Today: "Why let perfect stand in the way of the good? Just do something right away, I'm sure it'll be fine"

Tomorrow: "Yes, that new proposal would be more ideal, but we can't change the behavior now" / "Well why did you rush the feature instead of figuring it out first?"

The day after: "Why is this language so full of inconsistencies? It's like the designers just rushed something out the door to satisfy people. Pretty disappointing that they weren't willing to take their time to do it right."

@RyanCavanaugh I would agree with you on most design decisions but I think this is different because I don't think there is a "perfect" solution and silently ignoring possible errors does also not seem like the perfect solution. For this problem I would rather aim for a practical compromise.

Today: "Why let perfect stand in the way of the good? Just do something right away, I'm sure it'll be fine"

In all fairness, any decision made today or tomorrow wouldn't be "right away" considering this issue was opened in 2017...

The day after: "Why is this language so full of inconsistencies? It's like the designers just rushed something out the door to satisfy people. Pretty disappointing that they weren't willing to take their time to do it right."

Full? Are there really people here who sound like this?

@RyanCavanaugh > there's a 1:1 relationship between error codes and messages.

It seems to me like this is the source of our problems. Is this something that can be changed?

Has anybody proposed solving Ryan's problem by maintaining a mapping of "deprecated" / "refined" / "OBE" error codes? (Remember folks, naming things is one of the Hard Problems. Sorry.)

In his example, before TS7632 existed, the code would have been marked with TS2339. So, capture TS2339 -> TS7632 somewhere, once, and in future if there's code with @ts-ignore TS2339 and the compiler spits out TS7632, it walks up the tree and finds an equivalence, so the line is still ignored. There might be cases where this doesn't work out exactly, but it could at least address some of the concern.

My proposal is that an error dictionary is created. All errors would have an immutable number and mutable description. Any change in an error description would never break anything. No need for extra maintenance. The text editor would be able to use this dictionary to show a tooltip with the current error description on hover and that is it.

Ryan's example above isn't actually a change to an error, it's the introduction of a new, more detailed check that catches a subset of the errors that would previously have been caught. The critical thing is that the hypothetical TS7632 would not mean that TS2339 is completely obsolete. Consider

````ts
type Foo = { x?: number; }

type Foo2 = { y?: string; }

const f: Foo = {};
f.y = "hey";
f.z = true;
````

I assume Ryan is suggesting that, maybe in the future, the compiler will be smart enough to do string-similarity checks and give us a "did you mean?" style error. In that case, the f.y line could be marked with "Did you mean Foo2?", but the f.z line would still get the old error (TS2339) because you're simply referring to an unknown property.

That's why I suggested a mapping that captures this information. The new error message (TS7632) would have shown up as a more general message (TS2339) in a previous TS version, so knowing that means that @ts-ignore TS2339 should also always ignore TS7632. Of course, such a system could also work if a new error message number / string did completely replace an older one.

@thw0rted My impression is: if a more recent TS version is really catching a new kind of error, that was previously no cought because of an oversight or language limitation, it should never be suppressed by old error codes being ignored. IMO that is the whole point of this feature rquest.

Your example is not really a new error, it is an augumented way of dealing with an old error. I undersntand that, the way things work now, it would be required to use the new error code TS7632, thecnically making it a new error. But, this is not the true nature of this thing.

Would it make sense to separate them into what is an error and what is a smart suggestion to solve this error? In that case, we would have preserved the original error TS2339, which is not in fact obsolete. And there would be a list of possible smart suggestions for each error code.

@thw0rted I believe what you’re describing is what I proposed here, though I confess I haven’t followed this thread super closely of late. I think it addresses @RyanCavanaugh’s upgrade issue

Pretty much, Ethan. Hah, I even thumbs-up'd the old post back in October! The only difference is that I was imagining storing the "parent" or "alt" information as a tree -- it could be thought of as "ancestry".

I think this still makes the most sense. If all current errors are leaf nodes, then you can walk up to the root of the tree and each visited node is an error that the same line of code would have gotten under some previous version of the compiler. Storing it this way instead of as a flat array might be adding complexity for very little benefit, though.

@RyanCavanaugh if I understand correctly, your main issue is with the fact that TS could give a different error code for an issue in the future causing upgrade pains? However every TS version is already assumed to be a breaking change, so why not give users the ability to choose how much the ignore radius should be?

AFAIK the proposal is the following

@ts-ignore(?<comment> .*)? - Behavior remains as is Ignores the error on next line, if there is no error, tsc doesn't complain.
@ts-expect-error(?<comment> .*)? - Behavior remains as is. If there is any class of error on next line, error is ignored. If no error, then tsc says Unused '@ts-expect-error' directive.

New proposal @ts-expect-error (TS\d+): (?<comment>.+)? - Expecting a specific error and a reason why it's ignored. If in future there is a different error code, then user has to explicitly acknowledge that and change it.

Basically we're saying, let us decide how strict we want our ignore radius to be. In some projects, going yolo @ts-ignore makes sense, in some projects we want to tightly control ignored errors and slowly work on reducing the number of ignored errors. Having a smaller ignore radius is a big boon.

Every TS version upgrade is already a breaking change. There has been exactly 0 times, where a TS upgrade has just worked for me for our 100k+ lines codebase. So if you're fear is introducing more errors for a version upgrade, this hasn't been a big concern for us personally. Fixing @ts-expect-error issues with a new TS error code is a simple find replace. That's an easy class of errors to fix. I actually want to know when that happens and explicitly fix each one rather than it happening transparently.

Also this issue is something I feel strongly about and would be happy to champion a PR if Typescript core members agree it's something they are willing to accept.

This is something that would highly valuable to us. Having a ts-expect-error should always be a last resort, but if it comes to that then I would at least like to limit the scope of it as much as possible.

@nojvek These things are all true qualitatively, but there is a quantitative aspect that needs consideration. We totally expect that most very large codebases will see a dozenish breaks during version migrations, and that the maintainers of those codebases look at the breaks and mostly say "Yeah I can see how that was sketchy".

So if you're fear is introducing more errors for a version upgrade, this hasn't been a big concern for us personally

The reason you haven't had this problem is precisely because we've avoided adding features (like this one) that would create that scenario. I don't know what more to say on that; not getting wet in a rainstorm is a bad reason to throw away one's umbrella.

Here's a scenario that is entirely foreseeable:

  • Engineers at a large company with a TypeScript monorepo see this new feature for explicitly ignoring specific errors and "upgrade" their ts-ignores (which were inserted by an automated upgrade tool) to ts-specific-ignores in the name of "Now we know what's going on!"
  • This continues for a few years, and because TS generally issues either "X not assignable to Y" or "Can't call Z" errors at the top-level, those two error codes are everywhere
  • We find a neat way to be more specific in half of these errors, which necessitates a new error message and message number
  • Feedback on TS 5.7 is they're blocked on upgrading because there are so many new errors in this version that it's impossible to tell if anything bad is getting through

You're acknowledging the danger of this feature, saying that you accept the danger, and therefore there's no problem with the feature existing. The problem is, we're not just adding the feature for you, we're adding it for everyone, and there's no way to put a EULA sticker on this that says "FYI, version to version upgrades are totally YOLO if you use this". They're going to see it on Stack Overflow, stick 40 different ts-specific-ignores (which feel "safer" than a blanket ts-ignore) in places where they should used a tactical any instead, get burned on version N+1, and complain about how TS sucks at versioning and broke their app with no warning.

The downstream effects of "I accept the danger" thinking can already be seen with ts-ignore: people misapprehend what ts-ignore does, thinking it will somehow appear in declaration files. Or that they can use it to ignore TS telling them about a problem that will prevent correct emit. ts-ignore is a "last resort" feature and I would really argue that any line of code for which the ignored error is not immediately apparent by syntactic form alone is a red flag. There's little upside IMO to expanding its use or encouraging it to be more brittle unless there are use cases that simply can't be solved other ways.

Proposal: Having an opt-in way to limit ts-expect-error radius by specifying exactly which error to ignore.

If I understand correctly, the summary of your viewpoint is that TS team thinks that providing specific error code ignores is not a good future-proof solution. It should not be exposed to the user at all. Since it will regress the upgrade experience and TS team doesn't want to paint itself into a corner.

That's a reasonable argument. Ultimately you are the guardians of TS so it's your call (even if some of us may disagree). I appreciate the explicit clarification.

@RyanCavanaugh Then why have @ts-expect-error at all? If we don't want people abusing things then why were per-line @ts-ignores added back in 2.6 instead of having only global no-checks?

I admit the second example is a bit contrived; but for my first question, the documentation for ts-expect-error seems to be in direct conflict with the (good) points you were just making.

I feel conflicted, because I agree with the points you're making, but agree with the points made in the 3.9 documentation, and would be valuable to our team.

@RyanCavanaugh how would you respond to these excerpts:

Unfortunately if our tests are written in TypeScript, TypeScript will give us an error! ... That’s why TypeScript 3.9 brings a new feature: // @ts-expect-error comments. When a line is prefixed with a // @ts-expect-error comment, TypeScript will suppress that error from being reported; but if there’s no error, TypeScript will report that // @ts-expect-error wasn’t necessary.

Given this logic--that it's better to say expect-error than ignore in this type of test--then why isn't it EVEN BETTER to specifically say which error you're expecting?

Pick ts-expect-error if:

  • you’re writing test code where you actually want the type system to error on an operation

By adding a specific error code, instead of just blindly ignoring the line, the error can be PART of the test itself.

In addition, many of the points that you bring up (that I agree with) are similar to the ones given in this article for picking ts-ignore:

Pick ts-ignore if:

  • you have an a larger project and and new errors have appeared in code with no clear owner
  • you are in the middle of an upgrade between two different versions of TypeScript, and a line of code errors in one version but not another.
  • you honestly don’t have the time to decide which of these options is better.

You're right that a danger of adding specific errors is that you will use it to squash random errors in a codebase (point 1). Another danger you point out is how this can be abused and bite people in the future when updating (point 2).

From what I gather, having specific error codes amplifies the benefits listed in "Pick ts-expect-error if:", and exacerbates the problems in "Pick ts-ignore if:".

Just wondering what you think about this. Also, I'm not going to go through the initial expect-error PR threads, but during these debates were you on the side of not adding expect-error at all?

Also, I'm not going to go through the initial expect-error PR threads, but during these debates were you on the side of not adding expect-error at all?

Consider the fact that ts-ignore doesn't error on a "missing" error, though we could have easily made it do so. This was a very big discussion at the time we added that feature, with very similar characteristics to this one, and ultimately we went in the direction that would minimize upgrade pain. I think adding ts-expect-error before ts-ignore would have been a huge mistake; doing it in the order we did, with a long gap between, cemented ts-ignore as the "default" way to suppress an error, and then later having ts-expect-error meant it was fairly clear that you were opting in to a very specific behavior with reasonably foreseeable caveats.

I don't see the same analogue here, because it's not at all obvious that error codes are not necessarily stable between versions. C# has to do a ton of backcompat engineering to make sure their warnings are consistent version-to-version and we don't want to do that (though people are already speculating about how we should implement it). If we add this feature, we are guaranteed going to stoke ire from engineers who go all-in on it without realizing this, and there's nothing I see that can prevent it.

Maybe that future ire is worth it for the sake of whatever people are experiencing here, but frankly I have not seen the evidence for what kinds of problems people are encountering that this feature would solve better than other existing solutions. People just keep going in circles asking why it doesn't exist.

I get that it feels bad to ts-ignore some line of code that might acquire some additional error in the future, but it's instructive to read the original ts-ignore thread (which we also pushed back on for a long time) where 95% of people said they "needed" the feature for suppressing some particular error that they could have suppressed with a more tactical as any. We added ts-ignore with the intent that it be used for the remaining 5% that can't be suppressed by any existing type system mechanics; in this light I think the concern about oversuppression is somewhat misguided because there should be very very very few ts-ignores in your codebase, and because so few constructs require a ts-ignore, it should be very unlikely that they acquire additional errors later. I can't reason people out of their worries but we have to weigh "dev X will sleep better at night" vs "dev Y is facing an error cliff during upgrades because dev Z told them that they should always ignore specific error codes instead of using as any"

@RyanCavanaugh As a possible use case for this feature. I'm responsible for a pretty large (~100000 loc) project. During our incremental migration from JavaScript to TypeScript we had to use ts-ignore quite a bit and sometimes (by ignoring a complete line) we missed a problem that was accidentally hidden because ts-ignore ignores all errors. The option to restrict ts-ignore to the specific error that "must" be ignore could have prevented quite a few problems during the migration.

@RyanCavanaugh Very concisely written, and as someone that is only just thinking about this problem, you illustrated the history of these features in a way that really helped me understand where you're coming from. Thanks!

@denissabramovs That's not very helpful. Check out the thread starting here for some rationale

Was this page helpful?
0 / 5 - 0 ratings