Typescript: Ability to over power TS and ignore specific error by developer

Created on 30 Jun 2016  ·  150Comments  ·  Source: microsoft/TypeScript

A developer should be able to add a comment above a ts error such as

/// TS_IGNORE
let a:string = 1

and have the compiler not report that error...
there are certain scenarios the developer knows best and want to quiet down the error reports.

kind of like :any

regards

Sean

Fixed Suggestion

Most helpful comment

Just cast it (cast isn't official term, but same concept)

const foo: string = 7 as any;

Is that what your looking for?

All 150 comments

Agreed. Longing for something like Java's @SuppressWarnings, in particular for the case described here:

The following:

const typeMetadataKey = Symbol('type');

function type(name: string): PropertyDescriptor {
 return Reflect.metadata(typeMetadataKey, name);
}

Produces the error: Unable to resolve signature of class decorator when called as an expression..

When used as below:

class Person {
  @type('string')
  firstName: string;
}

The decorator does work as expected and will compile but gives the error above.

If you have thoughts on how this might be resolved happy to dig into it if someone would like to point to the right direction.

Just cast it (cast isn't official term, but same concept)

const foo: string = 7 as any;

Is that what your looking for?

I just gave an example, not really a case (I know all about casting) , I do have other cases such as
super being called after first line of constructor and other issues...

  • will make transition into TS easier from JS + sometime you change a lib and get tons of errors and you just want to clean things up as you know as the developer for the reason...

this is an important feature

So something like // tslint:disable?
Possibly even letting you turn on/off specific checks tsc performs?
_eg:_ const FooBar: string = 'rozzzly'; // tslint:disable-line camelcase

that would be awesome...

I don't know... I think that might be out of the scope of tsc. That's what linters are for.

there has to be able to "shut it up" :)

I think there's a case to be argued for suppressing errors/warnings on "experimental" features, like decorators, where the API is a bit volatile and the errors may not always be accurate. You get a (very specific) version of this just using the tsconfig "experimentalDecorators" field, but it only suppresses one type of warning.

To play my own devil's advocate, this could encourage new users of TypeScript to suppress warnings they do not understand instead of learning why the warning occurs. And with experimental features, everyone is sort of a new user - having the ability to suppress errors could make users complacent with bugs in new features, instead of opening issues.

Ultimately, I still want my Syntastic output to be clean. Which means suppressing the error. Of course, that would be _after_ I open the issue for a possible bug and try to learn more. ;)

The problem with "shutting it up" is you do not know what you get out of "it". so is let a:string = 1 a number or a string?, what if there is another declaration of a, does it merge or not? what if some one captured the type of this variable e.g. return {a} ; , should they be assignable to { a : number } or { a: string }, or both.

one fundamental thing, errors are all ignoble. errors do not block the generation of outputs, nor the tooling.

There are different mechanisms to allow you to suppress checking of certain parts of your code, e.g. any, type assertions (casts), and ambient declaration.

so for instance, if you have a library that has "invalid" definition, you can just remove it, and replace it with declare module "blah" { export = any }. or declare var $: any and you are good to go.

As i usually reply to these requests, i think your problem is not in suppressing the error. the real issue is you got an error that you do not find useful. suppress that does not solve the underlying problem it just covers it, and has ramifications of an inconsistent state with no warning. The right solution is to know what is the error you are getting? what library is it? and why the compiler is giving you an unuseful error...

And for this we need to know more about your use case.

We have done some work in TS 2.0 to resolve some of these underlying issues, for instance;

just use any, this is how "shut it up", merits of doing so (or actually a lack of thereof) is a different question

let x: PieInTheSky = <any> 'cake is a lie';

ok but again, the issue is not specifically on casting

<any> gives you vanila javascript with 100% freedom from all annoying things of TypeScript, so what else do you need?

in my case I call super not as fisrt line of constructor and need to quiet the error

Instead of trying to force it to accept an antipattern, why not write try something like this:

_ClassA.ts_

class A {
    constructor() {
        this.init();
    }
    protected init() {
        // does nothing by itself
    }
}

_ClassB.ts_

class B extends A {
    constructor() {
        super();
        console.log('rest of code from B\'s constructor');
    }
    protected init() {
        console.log('this runs before the rest of code from B\'s constructor');
    }
}

This is what makes typescript so awesome, _and also annoying_. It forces you to write better code and it makes you a better developer. Converting a project is not fun; you might consider it to be a developer's "initiation" or perhaps, "trial by fire." :laughing: But you learn a lot, and its totally worth it imho.

in my case I call super not as fisrt line of constructor and need to quiet the error

And make your code incompatible with ES6... Which is exactly why the main purpose of TypeScript is to take 👣 :gun: out of your hands.

If TypeScript is not interpreting something right, then it should be fixed versus "worked around". Now there are a few things where TypeScript is acting more like a linter and there is not yet a concept of "error" versus "warning". I can see suppressing warnings when they do come. Things like code after return and unused parameters should be warnings in my opinion, because they are syntactically correct (though stupid).

here's another case where I would love to have this feature:

interface Animal {
  numberOfLegs: number;
  // a gazillion more properties
}

class Dog implements Animal {
  breed: string;

  constructor(animal: Animal, breed: string) {
    Object.assign(this, animal);
    this.breed = breed;
  }
}

Right now there's an error from ts:

[ts] Class 'Dog' incorrectly implements interface 'Animal'
Property 'numberOfLegs' is missing in type 'Dog'

As you can see, the compiler is totally wrong, but I don't want to (and I shouldn't be forced to) copy all the properties from the interface just for the compiler's sake.

@DethAriel Basically what you're asking for is a way to express post condition side effects in the type system. That's interesting but I have a feeling it would lead to some terribly convoluted code.

@aluanhaddad Yup, I totally get that. But still, I do not see a non-ugly workaround for that except for copy-pasting the interface members, which is non-ideal at the very least. That's why I think that having the ability to shut up the compiler error output makes sense - we're all smart people here, and the compiler should trust us when we tell it to

Just use an interface+class combo

interface Animal {
  numberOfLegs: number;
  // a gazillion more properties
}

interface Dog extends Animal {
}

class Dog  {
  breed: string;

  constructor(animal: Animal, breed: string) {
    Object.assign(this, animal);
    this.breed = breed;
  }
}

Thx, @mhegazy , that worked indeed

What if the error can't be <any>ed away?

Im using the experimental bind syntax as discussed here https://github.com/Microsoft/TypeScript/issues/3508 and aside from not using it, I'm otherwise unable to get the compiler to ignore the error on each line before each :: operator (TS1128: Declaration or statement expected)

Im using the experimental bind syntax

this is really more than dismissing one warning. The parser does not support it, so the resulting tree is completely wrong, all of the compiler features from this point on will not work, so no type inference, no compatibility checks, no formatting, no completion, nothing. so you would be better off ignoring all errors, or just working in a .js file.

I am currently converting a huge JS project into typescript and after doing the conversion when I run gulp build command I see around 2000 TS errors during compilation and majority of the errors are related to Property not defined on a class or Module not defined. I think there must be some way to suppress these types of errors as the output JS files are getting generated.

This is exactly my case as well, I convert an app built with pre-ES6 modules-as-properties design, so I have a HUGE app.namespace1.namespace2.something.views.view -like global object.

I rewrite some part of it and I DO rely on the global app.* object and its different sub-elements in my code. All I get is a mass of "Cannot find namespace 'app'" warnings.

I have refactored all my global dependencies to a globalProxy.ts, so this is the only place I get the warnings, but it would be AWESOME to add a //TS-NO-WARNINGS at the top of this file to clean up the console from the obvious messages...

TS errors do not block the code generation. You could choose to ignore them, but what these are telling you is that the compiler can not assert the correctness of your code.

@zeeshanjan82 why not use --allowJs and migrate file by file? With that setup you won't get type errors from JavaScript sources. You can also use an ambient wildcard declaration to suppress module resolution errors like
_globals.d.ts_

declare module '*';

Here's another use case for error suppression.

The maintainers of the moment library forgot to add isoWeek as a valid string to the parameter enum for startOf and endOf methods. It was fixed in a subsequent release, but in doing so they completely refactored the way these units are handled, which would cause too much re-work on our end.

So we fixed the version of moment in place, but now we essentially can't use isoWeek because of TS throwing errors. So stuck between a rock and a hard place at the moment.

you could just add a local copy. say something as simple as:

// ./overrides/moment.d.ts
declare module "moment";
// tsconfig.json
{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "baseUrl": ".",
        "paths": {
            "moment": ["overrides/moment.d.ts"]  // override definition for moment
        }
    }
}

now the compiler will be checking against your local copy of override/moment.d.ts instead of the one coming with the package. obviously this can be a local copy of moment declaration file, or a small set of things you need.

I lack both the time and desire to maintain my own typings definitions for 3rd party libraries ;)

I lack both the time and desire to maintain my own typings definitions for 3rd party libraries ;)

And that is perfectly fine. just use declare module "moment"; which is the equivalent of declare var $: any for modules, and the compiler will not bother you about it again.

@mhegazy's suggestion is a very good one. It will take you about 20 seconds to do that. By the way, with respect to moment, they forgot a couple of units that I was using and they were very open to accepting my pull request.

The downside to adding declare module "moment"; is that you will no longer have any IDE intellisense or static type checking for any moment-related code. And the anys that arise tend to bleed out into surrounding code, shutting down many static checks there as well. It's a heavy price to pay for suppressing errors related to a single problematic enum value.

@aluanhaddad there was a pull request open to fix the issue, but it got closed in favour of another one, which introduced breaking changes (and still didn't add support for isoWeek), so not sure what happened there.

The point is that these issues are bound to arise more frequently in the future with the adoption of Angular 2 etc. so a way to supress particular errors would be useful I can imagine.

I have this issue with a node core library (net, node 6.9 LTS):

server = net.createServer({ pauseOnConnect: true }, function(connection) { ... }) 
// [ts] severity: 'Error'
message: 'Argument of type '{ pauseOnConnect: boolean; }' is not assignable to parameter of type '{ allowHalfOpen?: boolean; }'.
  Object literal may only specify known properties, and 'pauseOnConnect' does not exist in type '{ allowHalfOpen?: boolean; }'.'

And also with ioredis library:

var redis = new Redis(CONFIG.redis); 
// [ts] severity: 'Error'
message: 'Only a void function can be called with the 'new' keyword.'

As @yortus and @adamreisnz pointed, this is a common problem as definition files are not always correctly updated. Besides, If you have to sacrifice TS benefits using declare module "x"; why would you use TS in the first place?

You can also augment the module with the types that are missing so as to not lose intellisence.

Well, when I write:

if (typeof Symbol === "function" && Symbol.match) {
  // ...
}

The typescript compiler always reports an error Cannot find name 'Symbol' if target is es5, although this code indeed works well just as I expected.

So I agree that we badly need some control directives working in comment lines.

declare var Symbol: any;

@gdh1995 @mhegazy Or just use the real fix which is setting the lib flag to es2015.

@mhegazy Thanks. I find this works well:

declare var Symbol: {
  (description?: anyNotSymbol): symbol;
  readonly match: symbol;
};

@DanielRosenwasser Although es2015 adds these useful features, my project is limited to be compatible with es5 and then Symbol should be avoid in other files.

What I don't understand now is that the TypeScript compiler gives me errors even when I've written typeof Symbol === "function". Any advice?

One case I'd love to have to feature is for mocking dependencies:

// Test.ts

// Component to test
import {ComponentToTest} from './ComponentToTest';

// Dependency of ComponentToTest to mock
import {Dependency} from './Dependency';

// Mock to replace it with
import {MockedDependency} from './MockedDependency';

Dependency = MockedDependency;

This code has the desired effect of having the dependency be mocked within the tested component but TypeScript throws an obvious "Cannot assign to 'Dependency' because it is not a variable." error.

I'm sure the response is going to be that I'm barking up the wrong tree and should be using something like inject-loader but from my experience those solutions A) are a pain to get working/don't always work and B) aren't as simple as the above. As OP mentioned, sometimes the developer knows best. I know this is a hacky solution but it works and I'd love TS to just shut up in this case.

This code has the desired effect of having the dependency be mocked within the tested component but TypeScript throws an obvious "Cannot assign to 'Dependency' because it is not a variable." error.

this is an error in ES6. so some time in the future when engines support ES6 modules nativelly, your tests will need to be rewritten.

Alternatively you can have your ComponentToTest accept an argument for Dependency, and your tests can pass that, or have test hook that allows you to override the value of Dependency before invoking methods on ComponentToTest.

this is an error in ES6. so some time in the future when engines support ES6 modules nativelly, your tests will need to be rewritten.

Ah fair enough I'll drop it then as that requirement is tangential to this issue.

Alternatively you can have your ComponentToTest accept an argument for Dependency, and your tests can pass that...

I think this is what we ended up going with. It's just pretty lame to have to redefine the api for a class to make it testable but then I guess that's not a problem unique to TS at all.

Thanks for the feedback, @mhegazy

I'd like to override the check on the type of argument of a function.

My use case is quite simple, I have a function like this one:

function isValidId(s: string): boolean {}

that check if a string follows some rule.
It is used both internally and to validate user input - I'd like to write tests to see if it returns false when user inserts something that is not a string.

Strictly speaking, the function can accept anything as input because is able to manage it, but since we use it also internally I'd like to specify that we want a string

Therefore, I'd like something to suppress the error about wrong format in the tests

@rpadovani just use any:

expect(isValidId(78 as any)).toBe(false);

I could use this as well. We have a situation in which foo(bar: any, baz: any) is defined as part of a framework, but in some implementations of foo, bar is unused. With typescript error checking turned on, this throws an error because an unused variable is declared. It must be declared, because other versions of foo, bar is used.

@benjaminabbitt It seems that foo (_bar: any, baz: any) works for you: a name starting with "_" is not forced to be used.

Add: I believe that the ability to override/ignore special errors is important.

Something challenging here is that people keep showing up saying that want to suppress errors, posting code snippets, and getting effective in-code solutions for silencing those errors (or finding out their code really does have a problem). It's hard to design this feature without knowing what a truly problematic error looks like, or understanding which errors people want to suppress globally are.

What is the appropiate way of handling third party javascript code that we wish to include in our projects?

Consider the following scenario. There is a huge library that has not been published to npm and even if it were, using the library as is would make our application carry around lots of dead code (tree shaking can't help because they attach everything to an object).

Lets suppose that in this case its just not worth extracting this piece of code and publishing in npm. What other options do we have?

In my attempt to use this library I have extracted the code that my project needs and incorporated it to the project as a typescript file. The issue with this is that typescript checks this file and now gives a lot of errors for this file.

For this situation it would be great to have the /* ts:disable */ comment at the top so that typescript would know that we do not care about possible errors within the file.

Please note that my project does not commit any javascript files anymore and even if it did the build process would get more complicated trying to accommodate a javascript into the flow.

Does anyone have any advice as to how to deal with third party javascript code that needs to be hosted in a typescript project?

Does anyone have any advice as to how to deal with third party JavaScript code that needs to be hosted in a typescript project?

do not migrate them. leave the .js files as they are. create a .d.ts file for them instead. this is what .d.ts files are for any ways.

the .d.ts file can start with something as basic as:

declare var $: any;

then add to it as you see fit, and as your needs grow.

That is a good option if I were committing js files. Is there any other options for projects that ignore js files?

That is a good option if I were committing js files. Is there any other options for projects that ignore js files?

I am not sure i understand the question. JS files are ignored by default. so you opt-in adding files. again my recommendation is, for external code that is not yours, or for legacy code that you do not intend to change, do not bother converting it to TS. start by writing a .d.ts file for them. for this, start simple, with any's then add as you go.

I should have said that the js files are not being committed to the git repository, thus the reason of putting the code in a ts file. Anyway, I'll try to go the route you mentioned and force commit those js files.

you do not need to commit the .js files. let's say you are using a dependency say react. typically you will not commit react-0.12.0.js in your repo, but you want to use it. noramlly you would include this in a sccript tag from a CDN for instance. let's also say @types/react does not exist, or you do not want to use it. so in your project add a new declaration file call it declarations.d.ts and add:

declare module "react"; // just saying the module is of type any

this tells the compiler that there is a module called "react" and it will just use it, no need to include any .js files.

So if I want to use a small chunk of javascript (that is not available via npm/CDN) and I decide to commit it to my code base, I have 2 options:

Option 1: Keep the original code as a .js file and maintain a .d.ts file to handle types.

I think this doesn't work for @jmlopez-rod because he doesn't want to commit javascript code to his repo, and even if he did, he said it would make his build process complicated.

Option 2: Wrap the javascript in typescript and deal with all of typescript's errors.

This gets around the "complicated build process" because it will treat the code like typescript... but now we've got typescript errors, and we've circled back to the original discussion in this issue thread. Is this a valid use case for being able to disable typescript errors?

I think this doesn't work for @jmlopez-rod because he doesn't want to commit javascript code to his repo, and even if he did, he said it would make his build process complicated.

not sure i understand why it complicates your build process. you have a file "library.js" and "website.js", you decide to move "website.js" to "website.ts", just call tsc website.ts --outFile website.js and now we are back where it all started with two .js files. so do not see why it any more complicated than before.. it is just an extra build step at the head of the chain.

This gets around the "complicated build process" because it will treat the code like typescript... but now we've got typescript errors, and we've circled back to the original discussion in this issue thread. Is this a valid use case for being able to disable typescript errors?

I am not sure i fully understand why did you decide to switch this file to ts, and integrate it with your project, let types from it flow into your other components, build it along with your code, yet hold it to a different standard.

May be an example would be useful here. as @RyanCavanaugh noted, it seems to me that all these issues have well-defined ways to tell the compiler about the types and avoid errors instead of disabling errors all together and throwing the baby with the bathwater.

i couldn't understand why is this ambient declaration is not working for me.
i already defined the paths definition to the tsconfig.json like this
"paths": { "js-xlsx": ["./xlsx.d.ts"] }
but still i come accross that module not found error.
I tried to add 'fs', 'fs-extra' and that 'js-xlsx' libraries all of them didn't responded to my ambient declarations, castings or adding any types as here declare var $: any;
@mhegazy

you do not need to commit the .js files. let's say you are using a dependency say react. typically you will not commit react-0.12.0.js in your repo, but you want to use it. noramlly you would include this in a sccript tag from a CDN for instance. let's also say @types/react does not exist, or you do not want to use it. so in your project add a new declaration file call it declarations.d.ts and add:

declare module "react"; // just saying the module is of type any
this tells the compiler that there is a module called "react" and it will just use it, no need to include any .js files.

By the way i know that fs-extra library has the type definition like @types/fs-extra and for the js-xlsx we have ts-xlsx libraries but this is so weird that this tricks are not working for me :(

By the way i know that fs-extra library has the type definition like @types/fs-extra and for the js-xlsx we have ts-xlsx libraries but this is so weird that this tricks are not working for me :(

I think there is somethign else going on with your project.

c:\test\9448>npm install @types/fs-extra
[email protected] c:\test\9448
`-- @types/[email protected]
  `-- @types/[email protected]

npm WARN [email protected] No description
npm WARN [email protected] No repository field.

c:\test\9448>type a.ts
import { rmdir } from "fs-extra";
rmdir("c:/test");

c:\test\9448>type tsconfig.json
{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5"
    }
}
c:\test\9448>tsc --v
Version 2.2.0

c:\test\9448>tsc

c:\test\9448>echo %ERRORLEVEL%
0

yea maybe but, the main issue i couldn't understand is why i couldn't surpress compiler warnings with the given methods. By the way i have https://github.com/AngularClass/angular2-webpack-starter , base for my project

Suppressing errors doesn't necessarily mean introducing anti-patterns.

I'm getting an incorrect error,

error TS1005: '{' expected.

on this perfectly fine JSX:

<motor-node ref      = 'menu'
    absoluteSize     = `0, ${this.MENU_BAR_HEIGHT}, 0`
    >
    {menu}
</motor-node>,

It complains the the template string needs {. This should ideally be fixed, but until then, I would like to be able to suppress the error for good reason.

@trusktr, this error is a parse error. suppressing it does not change the fact that the compiler does not understand the code from this point on, and the shape of the rest of the file is in an undefined state. that means that even if this error is muffled, the types inferred, as well as other errors generated in this file or others are not correct.

That said. According to the JSX spec:

JSXAttributeValue :

" JSXDoubleStringCharactersopt "
' JSXSingleStringCharactersopt '
{ AssignmentExpression }
JSXElement

So I am afraid the error is correct and a JSX attribute can not have a string template literal. you can use absolteSize = {...} instead

this error is a parse error

Yep, that's why it should be fixed.

The output is absoluteSize: "0, " + this.MENU_BAR_HEIGHT + ", 0", which tells me the compiler things it is just fine.

Oh. Sorry then. I miss understood your comment. I thought you wanted the error silenced.

I did, but you're right, maybe I should better live with just adding {}.

In TS 2.1 (VS2017 RC) we get reported warnings coming from libraries JS files (sitting in /Scripts) folder -like TS7027. It would be nice to be able either suppress warn/errors from library files or at least to supporess them in some kind of global supression file (similar to C# GlobalSupressions.cs)

In TS 2.1 (VS2017 RC) we get reported warnings coming from libraries JS files (sitting in /Scripts) folder -like TS7027.

For unreachable code (TS 7027), set --allowUnreachableCode or set it in your tsconfig.json.

But is it possible to apply it only to library files. Because for "my code" I need it !

by using --alowJs it becomes your code. the compiler will suck it in, will transpile it to the suggested target, will concatenate it if you use --outFile.. it just that it has a .js extension. if it is "library" code, i would recommend creating a .d.ts for it and including this instead.

I'm not aware that we have switched on --allowJs - in VS2015 the exactly same project does not squiggle jquery.js, react.js files sitting in Scripts (and in fact referenced only from html page by