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

TS Parsing errors #1223

Closed
jods4 opened this issue Jun 26, 2020 · 11 comments · Fixed by #1237
Closed

TS Parsing errors #1223

jods4 opened this issue Jun 26, 2020 · 11 comments · Fixed by #1237

Comments

@jods4
Copy link

jods4 commented Jun 26, 2020

Tell us about your environment

  • ESLint version: 7.3.1
  • eslint-plugin-vue version: 7.0.0-alpha.6
  • @typescript-eslint/eslint-plugin: 3.4.0
  • @typescript-eslint/parser: 3.4.0
  • fork-ts-checker-webpack-plugin: 5.0.5
  • typescript: 3.9.5
  • Node version: 14.4.0

Please show your full configuration:

{
    "extends": [
      "plugin:@typescript-eslint/recommended",
      "plugin:vue/vue3-recommended"
    ],
    "parserOptions": {
      "parser": "@typescript-eslint/parser",
      "ecmaVersion": 2020,
      "sourceType": "module"
    },
    "rules": { "a bunch of rules": "off" }
}

What did you do?

<script lang="ts">
  import { h, FunctionalComponent } from "vue";

  export default <FunctionalComponent<{ header?: string }>>(
    function (props, { slots }) {
      if (props.header) {
        return h("div", { class: "header" }, [
          h("h3", props.header),
          slots.default!({ class: "header-child" }),
        ]);
      }

      const unwrap = slots.default!();
      return unwrap.length == 1 ? unwrap[0] : unwrap;
    }
  );
</script>

What did you expect to happen?
Anything but parsing errors.
This code is valid typescript and compiles fine, but eslint parsing chokes on it with parsing errors (see below).

There are a few other random parsing errors in other files but always in .vue files.
None of those seem related or new syntax. It just doesn't make sense to me.
Everything compiles and runs fine.

Unfortunately there are lots of moving pieces here, as I'm using eslint through fork-ts-checker, and I've got both the typescript and vue plugins layered on top of each other.

I put parser: "@typescript-eslint/parser" in parserOptions, as the docs says.

What actually happened?
This is one example of an error I'm getting:
image

I have a fair amount of complex TS in .ts files as well, but I'm only getting parser errors from .vue files. So I figure something must be wrong when the vue plugin is involved, although I have no idea what or why.

More examples of errors I'm getting:
image

image

@jods4
Copy link
Author

jods4 commented Jun 26, 2020

Just had a revelation.

Those errors are random but always pop up in code where a lot of brackets < and > are involved.

I am guessing that the parser that splits the .vue file into its parts (template, script) is confused by angle brackets and doesn't split parts properly.

The last error look a little bit like the script was cut short at the >.
The second to last looks like the parser is currently parsing html rather than TS (note the mention of &gt;).

As you can see in the issue, all my script blocks look like <script lang="ts">.
Interestingly, several files (but not all) that cause issue don't have a <template> (I'm still using .vue sfc to get the automatic <style> insertion).

@haoqunjiang
Copy link
Member

Guess it's the same issue as vuejs/vue-cli#4993 (comment)

@jods4
Copy link
Author

jods4 commented Jul 1, 2020

@sodatea I think you're right.

Looks like my hunch about angle brackets was on point: not because of HTML parsing but because of JSX (TSX) ambiguity.
Like the guy in the issue, I'm using lang="ts" and I don't care about TSX.

That as T workaround doesn't apply well in my code-based because some <T> are generic arguments, not casts. No luck here.

The other issue is closed but the problem seems to persist.
Do you know if it's tracked anywhere?

Some guy in the other issue says it might be a bug in typescript-eslint but I'm a little doubtful about that.
My reasoning is this: in the same project I have tons of TS code in regular .ts files that contains many generic arguments and casts and it all lints properly.

The only errors I have come from TS code extracted from .sfc files.
So my suspicion is that the problem is in the way that eslint-plugin-vue invokes @typescript-eslint/parser.

@haoqunjiang
Copy link
Member

I just realized the linked issue was caused by this line: https://github.com/vuejs/eslint-config-typescript/blob/9b3245240f3c97b46c3e0435b6ac1ed6041b732d/index.js#L11

It affects TypeScript's handling of .vue files.
https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/parser/README.md#parseroptionsecmafeaturesjsx

But I'm not sure where your problem is from. What about explicitly setting this option to false?

@jods4
Copy link
Author

jods4 commented Jul 1, 2020

@sodatea Great thanks! I was looking into those options and you beat me to it!

Setting ecmaFeatures: { jsx: false } explicitely solves the issue for me.

I'm gonna say eslint-plugin-vue should set this to jsx: false by default. It makes no sense to have JSX inside a SFC, where you're gonna use a template.
Or it would be even better if it could pass a correct file extension to eslint so that lang="ts" and lang="tsx" are handled properly, that'll cover even the craziest edge case.

Turns out that this setting is ignore for known file extensions, so setting this to false has no adverse effect even if you want to do some .tsx files in the same project. (I don't but just in case someone wants to.)

If you don't want to change anything in the plugin, it's probably nice to add a note in the getting started docs.
Feel free to close the issue.

@haoqunjiang
Copy link
Member

Yeah right. Didn't notice it's already set in the base config

Cc @ota-meshi

@ota-meshi
Copy link
Member

ota-meshi commented Jul 2, 2020

@sodatea @jods4 Thank you for finding the cause.

This jsx setting was set before I joined this project.

I looked in the commit history for the first time and didn't know why added it.

26f282e

In my opinion, it makes sense to change the base config so that JSX users themselves change the jsx settings, but It will be a breaking change for non-TS users using JSX or TS users using JSX who prefers "as" assertions.

Do you think you should change the base config? Or do you think it's enough to just document the jsx setting without changing them?

@jods4
Copy link
Author

jods4 commented Jul 2, 2020

@ota-meshi Note that the setting is only taken into account for unknown file extensions, e.g. .vue.
That's why my .ts files compile fine and that means that if you do .jsx or .tsx components they will compile fine as well.

The only case here would be someone doing JSX inside a .vue SFC but that seems an exception, as most people use SFC to write html templates.

So I'd say a better default is jsx: false (which is the default value of typescript-eslint) and if someone has JSX inside .vue files they should turn it on explicitly.

As it stands, typescript users can easily get into those obscure parsing errors because of casts or generics.

@haoqunjiang
Copy link
Member

I'm not sure whether there are more people encountering this problem or more people using script lang=tsx. But it definitely worth documenting.

@ota-meshi
Copy link
Member

Thank you for telling me your thoughts.

I think jsx: false is good, so I'd like to change the config in v7.0.0.alpha. This is because the number of TS users has increased compared to before the addition of jsx: true, so the situation is different from before.
I would also like to add a FAQ to the documentation on using JSX with config changes.

jods4 referenced this issue in vuejs/core Sep 16, 2020
)

* fix: should be able to parse decorators in script lang="ts"

* fix: should also support parsing jsx

Added to `compileScript` instead of `babelParserDefaultPlugins` because
it's not needed for template expression parsing
@MattiasMartens
Copy link

MattiasMartens commented Jan 28, 2022

Hey y’all, I seem to be getting the same/very similar issue (loader gives nonsense parsing errors on my Vue templates). I suspect it’s only a similar type of issue since parserOptions: { parser: '@typescript-eslint/parser', ecmaFeatures: { jsx: false } }
does not fix it; also removing parametric types from the <script> body does not make a difference.

However this is a complete show-stopper and I haven’t been able to find much online, so I thought I would post something here.

My .eslint.js file:

module.exports = {
  root: true,

  env: {
    node: true
  },

  'extends': [
    '@vue/typescript',
    'plugin:@typescript-eslint/recommended'
  ],

  parserOptions: {
    parser: '@typescript-eslint/parser',
    ecmaFeatures: { jsx: false }
  },

  rules: {
    
  },

  overrides: [
    {
      files: [
        '**/__tests__/*.{j,t}s?(x)',
        '**/tests/unit/**/*.spec.{j,t}s?(x)'
      ],
      env: {
        jest: true
      }
    }
  ]
}

Package versions:

    "@typescript-eslint/eslint-plugin": "^4.18.0",
    "@typescript-eslint/parser": "^4.18.0",

EDIT: This turned out to be unrelated to the issue; at some point I must have dropped the parser key. This is what the relevant lines of the config look like now:

  parser: 'vue-eslint-parser',
  parserOptions: {
    parser: '@typescript-eslint/parser',
    ecmaFeatures: { jsx: false }
  },

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants