Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New Typescript linting overriding user config and causing build failure #6871

Closed
ztolley opened this issue Apr 23, 2019 · 63 comments
Closed
Assignees

Comments

@ztolley
Copy link

ztolley commented Apr 23, 2019

The introduction of #6513 stops my application from compiling as it uses it's own Typescript linting rules instead of the rules I have in .eslintrc.js

Previous to CRA adding Typescript linting I created my own typescript lint config for eslint using @typescript-eslint/eslint-plugin and @typescript-eslint/parser along with airbnb and prettier rules.

Within the project there is typescript file generated by graphql-code-generator that breaks various linting rules, so has been added to a .eslintignore file. When I run eslint the project passes with no errors.

However, when I build the project or run it in dev mode 2 lint errors are raised, relating to the fact that import statements appear half way through the file. Using the .eslintignore file doesn't fix this problem, nor does updating my .eslintrc.js file to exclude the rule.

As a result I cannot build my project with CRA 3 and have had to revert to 2.

@wilcoschoneveld
Copy link

I had the same issue but I found a solution: https://graphql-code-generator.com/docs/plugins/add

In your codegen.yml, use the plugin add to insert an /* eslint-disable */ line to the start of the file.

Example:

schema: http://localhost:5000/api/graphql
overwrite: true
generates:
    ./src/generated.tsx:
        documents: ./src/graphql/*.ts
        plugins:
            - add: "/* eslint-disable */"
            - typescript-common
            - typescript-client
            - typescript-react-apollo
        config:
            noNamespaces: true
            enumsAsTypes: true
            withHooks: true
            noHoc: false
            noComponents: false

@jadbox
Copy link

jadbox commented Apr 23, 2019

I'm having the same issue: tslint.json rules seem to be ignored now in v3 and overwritten by the new defaults. Please send help.

@proluk
Copy link

proluk commented Apr 24, 2019

We've also upgraded to the latest react-scripts (3.0.0) in order to get rid of high vulnerabilities, but it broke our tslint configuration. No .eslinttignore or .eslintrc are working and adding comments to every file that disables eslint seems really bad.

@ianschmitz
Copy link
Contributor

Our ESLint configuration is not currently configurable (as has always been the case) and is documented here: https://facebook.github.io/create-react-app/docs/setting-up-your-editor#displaying-lint-output-in-the-editor. Any changes you make to your configuration file will only affect your editor integration but not the Dev server or prod builds.

We haven't ever supported TSLint so I'm not sure how the other comments are related.

@raptor1989
Copy link

Ok, but why can't I configure my own rules? To comply with your rules, I would have to rewrite my code. Stupid breaking change... I also came back to revert to 2.

@jadbox
Copy link

jadbox commented Apr 24, 2019

@ianschmitz I think the confusion was that Typescript folks where using TSLint since the react-scripts had no TS linting support. We have entire projects built using custom rules, but now since TS linting is supported in v3, we are all stuck with pages of warnings and/or broken builds. While the JS community had somewhat the ease of greenfield development using react-scripts' blessed linting rules, the TS community is now coming onboard with custom opinionated rulesets for large existing projects.

Proposals:

  1. provide a way to completely disable linting in production and live server (maybe this already exists?)
  2. provide a way for custom eslint overriding rules (both JS/TS)

On a community aside, I didn't realize the react-scripts didn't allow JS projects to customize the linting rules. As someone that disagrees with the defaults of most linters (as well as my team), it feels very heavy-handed to including linting by-default without a way to customize. (obviously there's ejection, but it's far from an easy path to own)

@ztolley
Copy link
Author

ztolley commented Apr 24, 2019

I purposely use eslint as the Typescript team stated that that is their preferred solution and are putting effort into eslint support, though I'm sure some folks here use tslint.

But back to the comment by @ianschmitz . I understand that the linting config, which now supports Typescript, is it's own thing and doesn't use the lint config a developer may add but my issue is that this recent change broken my code, and it seems others too. I know moving to 3 means possible breaking changes but this wasn't in the release notes, probably because no one realised.

The workaround @wilcoschoneveld mentioned will get me out of this for now but as @jadbox says, linting is opinionated and projects have rules in place and probably went through their own pain getting them agreed. I too think that having CRA linting errors stop a build is too heavy handed. I worry that option 2 would be too difficult to do and maybe the quickest short term solution would be to add a config option to allow a build to complete even when there are lint errors and maybe another to allow linting to be disabled so the user can use their own.

@dannycochran
Copy link

dannycochran commented Apr 26, 2019

@ianschmitz is this just a matter of looking to see if a user has provided an .eslintrc file here? if they have one, CRA could load it, otherwise use the existing one as a default?

https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/config/webpack.config.js#L324

@ianschmitz
Copy link
Contributor

@ztolley The baked in linting configuration is how we've always provided CRA, including adding new rules between major versions which is similar to what is being mentioned in this thread. This thread is slightly different in that some (including myself) were using TSLint prior to 3.0. To clarify, we did mention that the added TypeScript linting was in the 3.0 release notes and listed as a breaking change.

I will discuss the possibility of extending the ESLint config with the team which i think would satisfy what most of you are looking for (i know i would use it personally), but i can't promise anything as it's a fairly significant change to how we've been providing CRA for a few years now.

@dmitryxcom
Copy link

dmitryxcom commented Apr 26, 2019

This is very frustrating.
The fix seemingly solves very few, if any, actual problems people report, while going pretty much against what is purports to fix, i.e. #5641, which very clearly shows interest for a configurable tslint. In addition it enforces rules that are NOT in the list of "things that we want", such as unknown-ref,
in a few examples that I looked, it seems to ignore things defined via definitely typed @types that have something like
declare global {
x: Type;
}
x is being reported as unkonwn.

@estaub
Copy link

estaub commented Apr 26, 2019

@dmitryxcom Just to be clear, by "the fix", are you referring to 3.0, or to some subsequent PR?

@dmitryxcom
Copy link

@estaub I mean #6513

@gaearon
Copy link
Contributor

gaearon commented Apr 27, 2019

TSLint is getting deprecated, as its own homepage says:

Screen Shot 2019-04-27 at 01 46 08

I'm not sure what longer term strategy you're suggesting if even TypeScript itself is officially recommending a move to ESLint (which we have done). Create React App 3.0 aligns the linting rule with the same rules that have always been enabled in the JavaScript version.

If there are specific rules that are causing you trouble, I'd appreciate a more detailed writeup about specifics. There is no need to make this issue emotional. We're all people and are trying to do what's good for the project and most users. I'm sorry upgrading created issues for your existing setups — but eventually you'd have to make those changes anyway, as TSLint will be deprecated by its maintainers.

@gaearon
Copy link
Contributor

gaearon commented Apr 27, 2019

As someone that disagrees with the defaults of most linters (as well as my team), it feels very heavy-handed to including linting by-default without a way to customize. (obviously there's ejection, but it's far from an easy path to own)

I'd like to emphasize Create React App ships with a very relaxed rule set that only includes the bare minimum of things that protect against real bugs. We don't ship any stylistic rules or rules that are largely a matter of opinion. (The only exception is the React Hooks rules which we intend to enforce more strongly.)

We have entire projects built using custom rules, but now since TS linting is supported in v3, we are all stuck with pages of warnings and/or broken builds

Can you give me an example of which rules you're bumping into?

@dmitryxcom
Copy link

dmitryxcom commented Apr 27, 2019

TSLint has been deprecated, and will not be maintained in the future. Please read the announcement from the TypeScript team regarding that.

and similar. While the deprecation is on the roadmap the current state of eslint does not allow it to be a drop-in solution since it misses the most important type-based TS checks tslint provides (and for the majority of other checks there's prettier). Making it the default in CRA is a bit too early a call, in my opinion, and that is what is frustrating about the decision to make it default in CRA3, which goes beyond being opinionated, and becomes pushy and limiting.

The deprecation notice clearly warns about eslint not being ready as a replacement:

This will not be an immediate deprecation; on the contrary, there is a lot of work to do to ensure a smooth transition to the new tooling without any regressions. There are features, test suites, and conveniences in TSLint which we hope to retain in the migration. There may be a period of time when there is overlap between the two tools and TSLint early adopters are recommended to run both linters to ensure full code check coverage (to a reasonable degree such that performance doesn't suffer drastically).
-- source: palantir/tslint#4534

but eventually you'd have to make those changes anyway, as TSLint will be deprecated by its maintainers.
I'm not sure what longer term strategy you're suggesting if even TypeScript itself is officially recommending a move to ESLint (which we have done

My strategy is to wait until esint is fully compatible, which I argue should be CRA strategy as well, or at least, CRA should provide an opt-out of ts eslint linting until that point is reached. Like you point out, the migration will happen eventually, but the time is not here yet.

If there are specific rules that are causing you trouble, I'd appreciate a more detailed writeup about specifics.
Can you give me an example of which rules you're bumping into?

I've opted out of CRA3 for now with a todo to file specific bugs if I find the time to do that work.

@dmitryxcom
Copy link

dmitryxcom commented Apr 27, 2019

I think it would be very reasonable to expect at least an opt-out until palantir/tslint#4534 and typescript-eslint/typescript-eslint#36 are closed

@dmitryxcom
Copy link

dmitryxcom commented Apr 27, 2019

Do I understand correctly that with #6915 there's currently no way to configure eslint? In which case, it can not be considered a tslint replacement at this point?

@ztolley
Copy link
Author

ztolley commented Apr 27, 2019

@ianschmitz Thanks for your reply and your patience. In my case I can get around it for now. I feel for the people who can't and I think an opt out would help them and be a quick win.

I also agree that a measured approach to addressing this and providing further flexibility is the right thing to do, rather than rush into a solution that makes things worse with regards to picking up a users config.

@eemelisoderholm
Copy link

I would imagine more than a handful of organisations have CRA-based projects with tslint.json file referring to their own common ruleset as "extends": ["@company/tslint-config-company"].

CRA 3 breaks any such project by enforcing a different set of rules and it's a shame to eject because of it.

While moving towards ESLint and providing some reasonable defaults for linting are both very reasonable goals, I think the existence of local tslint or eslint configuration files should definitely override this.

It's likely most developers aren't even aware of TSLint's future deprecation plans yet, so this is likely a very unpleasant surprise while updating projects dependencies.

Perhaps a more reasonable migration path would be to display a deprecation warning about TSLint configuration, so users can start migrating their rules.

@ianschmitz
Copy link
Contributor

You're welcome to continue using TSLint alongside CRA if you wish. I do so myself for a few promise rules that aren't in ESLint yet.

How does CRA break your project? What rules are causing issues for you?

@dannycochran
Copy link

@ianschmitz in my case, the linting is not necessarily breaking, but confusing in a few ways:

  1. VSCode picks up my local .eslintrc.js file, so VSCode provides linting warnings and autofixes from that file. My linting tasks from package.json also use my local .eslintrc.js file. CRA, however, uses its own config and reports separate warnings in the terminal and browser console. It's confusing for my project to have two essentially two different linting rule sets, and there are certain rules that come with CRA that I just don't want (see below), or aren't included in the default config.

  2. When creating a production build, my builds fail since process.env.CI = true and warnings are treated as errors. I'm aware I can disable this.

@gaearon rules I'm bumping into:

no-unused-vars - I have unused vars all the time when I comment out code during development, so while I like the idea of this rule, I generally find it a hindrance while developing and turn it off. What I used to do with TSLint was occasionally turn the rule on, run my linter to clean up unused code, and then turn it back off.

array-callback-return - I'm getting this from an arrow function that does a switch case on a known TypeScript string, so I have no default return value.
default-case - Same as above. Example:

          titles.sort((titleA, titleB) => {
            switch (titleSortBy) {
              case 'name': {
                return getAlphabeticalSortValue(titleA.name, titleB.name);
              }
              case 'type': {
                return getAlphabeticalSortValue(titleA.type, titleB.type)
              }
              case 'launchDate': {
                return getNumericSortValue(titleA.launchDate, titleB.launchDate);
              }
            }
          });

It looks like @ianschmitz already addressed this, though I'm not sure that PR also covers array-callback-return ?

exhaustive-deps - I'm new to hooks here so maybe I'm doing something wrong, but it seems like you shouldn't need to pass in certain types of functions, like dispatch or action creators like fetchTitle:

  // only run this effect when props.movieId changes
  useEffect(() => {
    props.dispatch(fetchTitle(props.movieId));
  }, [props.movieId]);

The example here makes sense since doSomething is closure containing someProp, but in this case I'm not sure the linting rule makes sense?

Even if I adopted all the rules above, there are additional rules I like that aren't in the CRA configuration, such as import/order –– it looks like the default CRA config has no opinion about import ordering, for instance.

@ianschmitz I understand there may be a compelling philosophical reason to not allow linting customization in CRA, but is there a compelling code complexity reason? It seems like loading a user's custom .estlinrc file would be relatively straightforward (per my comment above), but I'm not nearly familiar enough with the codebase to make that judgment. Would it have consequences on other parts of the CRA build pipeline?

@BhanuNexus
Copy link

facing a similar issue, excluded node_modules but it is still linting src folder in one of the npm packages.

@olee
Copy link

olee commented May 4, 2019

There also are code breaking rules in the current configuration!
Using an overloaded constructor definition in a typescript class like this will throw an exception from eslint:

class Test {
    constructor(a: number, b: string);
    constructor(b: string);
    constructor(aOrB: string | number, b: string) {
      if (typeof aOrB === 'number') ...
    }
}

This code will break with this error:

TypeError: Cannot read property 'body' of null
Occurred while linting <my test file>
    at Array.forEach (<anonymous>)
    at Array.forEach (<anonymous>)
    at Array.map (<anonymous>)

This issue was reported here typescript-eslint/typescript-eslint#420 and the only correct solution is to disable no-useless-constructor and enable @typescript-eslint/no-useless-constructor instead which I can't do.
It really should be possible to disable / customize linting rules.

EDIT:
Same seems to happen for overloaded functions in general.
I tried to define a static Create function with my needed overloads instead, however this also throws a linting warning (but at least it does not crash).
The rule no-dupe-class-members should be disabled for typescript linting because typescript compiler already does that: typescript-eslint/typescript-eslint#291

  Line 52:  Duplicate name 'Create'                     no-dupe-class-members
  Line 53:  Duplicate name 'Create'                     no-dupe-class-members
  Line 54:  Duplicate name 'Create'                     no-dupe-class-members

@bradzacher
Copy link

Taking us way off topic here (sorry everyone :), buuuuut...

they'll be forced to handle it in the switch statement at compile time.

That only occurs if you strictly type the function return and/or use noImplicitReturns.

This can then be handled by instead using the following helper, which will trigger a type error if someone forgets to add a case to the switch because TS won't do an implicit never cast:

function assertIsNever(value: never) {
  return new Error(`Unexpected value ${JSON.stringify(value)}`);
}

/////

default:
  // Argument of type '"b"' is not assignable to parameter of type 'never'.
  throw assertIsNever(value);

playground

@ianschmitz
Copy link
Contributor

@dannycochran There isn't currently a PR up for extending the ESLint config yet, but internally we are looking into it.

@bradzacher ESLint's no-unused-vars rule is disabled in the TypeScript rules. We use the typescript-eslint rule instead and it is set to warn.

'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': [
'warn',
{
args: 'none',
ignoreRestSiblings: true,
},
],

The linting rule provides a nicer DX as the TypeScript noUnusedLocals option causes the type checking to emit an error which is quite disruptive during development. By using the linting rule and setting it to warn, we can still inform the developer in the terminal/dev tools, but not block them by showing the error overlay. However users are free to enable the compiler option if they wish.

@bradzacher
Copy link

@ianschmitz - sorry, I meant that our rule (@typescript-eslint/no-unused-vars) isn't 100% correct. Typescript has some very complicated scope logic, so there are a number of false positives.

What I was meaning is that our no-unused-vars is great for development because it can be non-build-blocking, but it's not great as a production build blocker because of the false positives.

The best experience is to use our no-unused-vars in dev only, and noUnusedLocals for the prod build only.

@ianschmitz
Copy link
Contributor

We have started a PR to extend ESLint config: #7036.

@bradzacher I see what you're saying now. Thanks for clarifying. I'm not sure what the best path forwards is. Perhaps with #7036, users could disable that rule if it's causing issues for them. They could enable noUnusedLocals as a replacement, but it would be active during development currently which is a little unfortunate.

@carpben
Copy link
Contributor

carpben commented May 27, 2019

As a community it is important to be respectful to one another.
I understand that upgrading, having to revert, and even noticing changes you don't support is frustrating, communicating rudely with open source maintainers/contributors doesn't make much sense to me, and isn't helpful either.

As for the issue itself, I'm currently using version 2.1.5. I can't continue using this version since npm audit reports 5 high vulnerabilities of dependencies of this version (handlebars, tar). On the other hand I use and relay on TSLint so I can't yet upgrade to version 3.

@zwhitchcox
Copy link

Is there any way to completely disable tslint?

@zwhitchcox
Copy link

I tried deleting

  "eslintConfig": {
    "extends": "react-app"
  },

@zwhitchcox
Copy link

zwhitchcox commented Jul 6, 2019

@ianschmitz

We haven't ever supported TSLint so I'm not sure how the other comments are related.

I am getting an error

Failed to compile.

./src/AddressAutoComplete.tsx
  Line 7:  'google' is not defined  no-undef
  Line 8:  'google' is not defined  no-undef

Search for the keywords to learn more about each error.

@danielkcz
Copy link

@zwhitchcox https://github.com/arackaf/customize-cra#disableeslint is probably the best option right now.

@mbaranovski
Copy link

How can I run typescript-eslint on pre-commit? Let's say using lint-staged. I found the CRA linters config at package: node_modules/eslint-config-react-app but when running it simply with eslint it does not understand the TypeScript syntax.

@danielkcz
Copy link

@mbaranovski I've just executed yarn eslint src on typescript project and works just fine. Typescript is just a plugin to eslint so there shouldn't be any change in how you execute it.

@mbaranovski
Copy link

@FredyC I dont have any eslint rules defined in my project, I'm only using CRA 3.0.0 defaults. When running eslint src or yarn eslint src I am getting ESLint couldn't find a configuration file. To set up a configuration file for this project which makes sense. I've tried to run eslint and point to eslint config placed in node_modules/eslint-config-react-app but I need to parse typescript first somehow.

@danielkcz
Copy link

@mbaranovski You need to do this ... https://facebook.github.io/create-react-app/docs/setting-up-your-editor#displaying-lint-output-in-the-editor

@mbaranovski
Copy link

Thanks @FredyC it works now :)

@danielkcz
Copy link

Hm, I take it back, I thought that eslint src works, but it's actually false positive. It does not check any TS files. When I execute eslint --print-config src it uses babel-eslint and doesn't match against Typescript files.

Running eslint --print-config src/index.tsx actually shows parser @typescript-eslint/parser used.

I had to run the ugliness of eslint .\src\**\*.ts .\src\**\*.tsx to make it check correctly.

This should be definitely documented. It's great we get lint checks with start script, but that's overkill if we want to just check files, especially in CI service.

@mbaranovski
Copy link

I'm using simply a glob pattern, ./src/**/*.{ts,tsx}
plus maxwarning option equal to 0 to prevent commits when there are any warnings (by default warnings on CI are treated as errors).

@babakness
Copy link

Having the ability to define/override rules in eslintrc.json is pretty important...

@alexfoxgill
Copy link

alexfoxgill commented Jul 23, 2019

I like to structure my TS code using namespaces to group functions, for example:

export type Option<A> = Some<A> | None<A>

export namespace Option {
  export const none = <A>(): Option<A> => new None<A>()
  export const some = <A>(a: A): Option<A> => new Some<A>(a)
}

...

CRA seems to want to tell me how to write my code:

Compiling...
Failed to compile.

./src/util/Option.ts
  Line 3:  ES2015 module syntax is preferred over custom TypeScript modules and namespaces  @typescript-eslint/no-namespace and namespaces  @typescript-eslint/no-namespace

This is a purely stylistic point - giving a compilation error! - and actually one that makes zero sense, since namespaces are actually useful.

How do I get rid of this useless error?

(the workaround, for those others frustrated with this limitation, is to declare a const object with a property for each namespace member)

@danielkcz
Copy link

danielkcz commented Jul 23, 2019

AFAIK namespaces are still not supported.

Edit: Ah, so there is some experimental support ... https://babeljs.io/docs/en/babel-plugin-transform-typescript/

@talaikis
Copy link

This one proves the rule that software updates are the scams to sell further fixes for those updates.

@loganknecht
Copy link

loganknecht commented Aug 11, 2019

Hi. I'm just chiming in here because I got side-swiped by having to upgrade create-react-app from version 2.1 to 3.0 this weekend, for a project that is fairly mature, in order to fix my build times for my react app.

Please correct me if I'm wrong, but my understanding is:

  • my upgrade moves me away from react-scripts-ts to react-scripts
  • I can have an .eslintrc.json file to help my IDE/local development environment
  • I can't disable react build script warnings because the team thinks that's inappropriate, and react-scripts provides no ability to do so
  • Which means all of my builds will have failures because my development settings don't align with the build settings
  • There is no clear work around

If this is is the case, I am beyond disappointed in what the perceived user experience is for this.

A developer is always going to want to toggle these settings. All of these settings may or may not directly apply to specific projects. And now the product create-react-app is blasting noise every time I build which makes it impossible to discern what is a failure, and what is actually something I need to address. Which means that pushes all of that output into my IDE. And even worse, is these are displayed as warnings in a lot of instances when they should be failures blocking me until I fix them.

Folks, this is terrible, and I would like to articulate that this lack of support is a big disappointment that makes me very keen to move away from create-react-app as it basically removes a significant amount of functionality that made it attractive in the first place.

@MattMorrisDev
Copy link

If you want to totally disable the build warning overlays, you can add this css to your project as a short term / quick fix:

iframe[style="position: fixed; top: 0px; left: 0px; width: 100%; height: 100%; border: none; z-index: 2147483647;"] {
        display: none;
}

@bugzpodder
Copy link

3.1 comes with support for custom eslint configuration, should that solve most of the problems here?

#7036

@StJohn3D
Copy link

StJohn3D commented Aug 21, 2019

@bugzpodder Over an hour later and I haven't had any luck getting that to work. Am I missing something?

.env

EXTEND_ESLINT=true

package.json (The relevant parts)

{
  "dependencies": {
     "react-scripts": "3.1.1"
  },
 
  "eslintConfig": {
    "extends": [
      "react-app",
      "eslint-config-react-app"
    ],
    "rules": {
      "no-useless-escape": "off"
    },
    "overrides": [
      {
        "files": [
          "**/*.ts?(x)"
        ],
        "rules": {
          "no-useless-escape": "off"
        }
      }
    ]
  }
}

@djkirby
Copy link

djkirby commented Aug 22, 2019

@StJohn3D I would double check that there aren't any errors being swallowed -- #7530.

Might wanna check by adding this line in to your node_modules/react-scripts/config/webpack.config.js https://github.com/facebook/create-react-app/pull/7530/files#diff-dc0c4e7c623b73660da1809fc60cf6baR349

@ianschmitz
Copy link
Contributor

@ztolley have you tried enabling extending our built-in ESLint config as described here: https://create-react-app.dev/docs/setting-up-your-editor/#experimental-extending-the-eslint-config?

Let us know so I can close this if it solves your issues.

@lock lock bot locked and limited conversation to collaborators Oct 23, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests