microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
99.82k stars 12.35k forks source link

Support @ts-ignore for specific errors #19139

Open ghost opened 6 years ago

ghost commented 6 years ago

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.

megan-starr9 commented 6 years ago

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

Ristaaf commented 6 years ago

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.

alexburner commented 6 years ago

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.

stweedie commented 6 years ago

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)?

Busyrev commented 6 years ago

@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?

thw0rted commented 6 years ago

@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...)

wosevision commented 6 years ago

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".

HolgerJeromin commented 6 years ago

@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.

wosevision commented 6 years ago

@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.

jlengrand commented 6 years ago

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.

mjomble commented 6 years ago

@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.

jlengrand commented 6 years ago

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

ghost commented 5 years ago

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.

ilyakatz commented 5 years ago

👍

glen-84 commented 5 years ago

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).

Busyrev commented 5 years ago

@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.

glen-84 commented 5 years ago

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.

pungggi commented 5 years ago

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

Busyrev commented 5 years ago

@pungggi its easy to do here https://github.com/Microsoft/TypeScript/blob/master/src/compiler/program.ts#L1688 just return fasle is you dont want to see this error This place in my fork https://github.com/Busyrev/TypeScript/blob/publicChecker/src/compiler/program.ts#L1521

pungggi commented 5 years ago

nice! thank you!

doberkofler commented 5 years ago

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

tjfryan commented 5 years ago

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

bmeck commented 5 years ago

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:

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.

doberkofler commented 5 years ago

@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.

mnn commented 5 years ago

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.

DanielSWolf commented 5 years ago

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.

glen-84 commented 5 years ago

@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.

doberkofler commented 5 years ago

@glen-84 sounds good to me!

Busyrev commented 5 years ago

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.

DanielSWolf commented 5 years 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.

bmeck commented 5 years ago

@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?

DanielSWolf commented 5 years ago

@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.

fantapop commented 5 years ago

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

zephraph commented 5 years ago

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.

trusktr commented 5 years ago

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)
johnculviner commented 4 years ago

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!

ethanresnick commented 4 years ago

@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.

NetOpWibby commented 4 years ago

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();
thw0rted commented 4 years ago

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.)

NetOpWibby commented 4 years ago

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.

shellscape commented 4 years ago

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.

NinthDesertDude commented 4 years ago

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.

vpanta commented 4 years ago

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.

RyanCavanaugh commented 4 years ago

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

NetOpWibby commented 4 years ago

@RyanCavanaugh Then why not close this issue?

RyanCavanaugh commented 4 years ago

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.

NetOpWibby commented 4 years ago

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.

thw0rted commented 4 years ago

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?

doberkofler commented 4 years ago

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.

cantiero commented 4 years ago

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.