vuejs / vetur

Vue tooling for VS Code.
https://vuejs.github.io/vetur/
MIT License
5.75k stars 594 forks source link

The script lang=ts showing misleading errors in .vue files #1431

Closed fairking closed 5 years ago

fairking commented 5 years ago

Info

Problem

image

Reproducible Case

Try vue js ts project from scratch using @vue/cli with option typescript and check whether vetur <script lang="ts"> is properly validating model properties, vuex getters and actions.

Also my tsconfig.json looks like this:

{
    "compilerOptions": {
        "target": "es5",
        "module": "esnext",
        "strict": true,
        "jsx": "preserve",
        "importHelpers": true,
        "moduleResolution": "node",
        "experimentalDecorators": true,
        "esModuleInterop": true,
        "allowSyntheticDefaultImports": true,
        "sourceMap": true,
        "allowJs": false,
        "baseUrl": ".",
        "types": ["webpack-env", "jest"],
        "paths": {
            "@/*": ["src/*"]
        },
        "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
    },
    "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "tests/**/*.ts", "tests/**/*.tsx"],
    "exclude": ["node_modules"]
}
jackkoppa commented 5 years ago

I have bad news, unfortunately - the standard approach to Vuex components simply doesn't play well with lang="ts" components 😞

There's a good reason for it: when Vue provides helper functions to, for example, mapActions so that you can use this.success in your component, that's something that only Vue will understand at runtime in the browser. You're giving Vue a set of strings, and relying on Vue to correctly map those to make the correct methods available in your component.

But there's no way for TypeScript (& thus no way for Vetur) to know what those strings are supposed to mean at build time. This is a Vue + TypeScript issue, rather than a Vetur issue.

A few main options:

  1. Don't use lang="ts" in components that reference Vuex. This is what we do for our projects that didn't start as TS projects; in those cases, we only use TS components when they don't reference Vuex
  2. Use a wrapper for Vuex that is type-safe; this will add some boilerplate for each Vuex module, but works well, and gives full type safety (& no TS errors) when accessing Vuex. Recommendation: https://github.com/jackkoppa/typesafe-vuex
  3. Use the class syntax for TS components, and a Vuex helper package that uses decorators to help access Vuex modules: https://github.com/ktsn/vuex-class I wouldn't particularly recommend this, since Vue is generally moving away from class components

Certainly, the simplest answer is above is #1, with the obvious downsides in larger projects, that you'll have lots of untyped components. But, the nice thing about Vue is it gives us that choice, by allowing both JS & TS components in the same project

fairking commented 5 years ago

Hm.

  1. I cannot see a problem to interpretate script inside <script lang="ts"></script> as TypeScript. CLI can extract the script from the vue and put it into separate file (eg. *.vue.ts) before running.
  2. I am not sure about vuex actions but I assume properties user and userDemo should work with Vetur as it is a part of Vue so Vetur has a purpose to actually solve all those vue-specific syntax and validation. Otherwise I don't need Vetur just to validate TypeScript.
  3. I think all that validation Vue/TS is very important for Vue itself as to develop larger applications require strong type language like TypeScript. Nobody wont use Vue if it's loosing TS strenght and potency. They will rather choose Angular or React. Nobody will start enterprise app in Vue/JS or in Vue/TS without strong prebuild validation. I think Vetur is also should be responsible for this and help Vue with growth.

Regards

jackkoppa commented 5 years ago

Oh, for sure, most of the TypeScript interpretation should work! And Vetur works just as well as the Vue CLI when compiling our lang="ts" components. When you run build with the CLI, for example, you'll find the same errors that you see in Vetur right now.

The good news is that you can solve a number of the problems that you see in your screenshot by using Vue.extend({}); it's required for TS components to get correct type inferences for Vue. Documented here: https://vuejs.org/v2/guide/typescript.html#Basic-Usage

And finally: you're completely right, that devs on the largest projects really need great TS support. It's certainly the case on our team. Vue is trying to address some of the things that make it very easy to get started with, but very hard to add accurate TypeScript support for (like mapping Vuex methods, and also mixins) with their composition RFC. It's going to be an additional way to instantiate components, and it will have perfect TypeScript support. Check it out! https://vue-composition-api-rfc.netlify.com/#basic-example

(I should mention - if you like the above composition approach, you can already start using it with the composition plugin. I wouldn't recommend that quite yet, since it's pretty early on, but it is an option - https://github.com/vuejs/composition-api/)

fairking commented 5 years ago

Thanks for your optimistic reply. I would definitely look at the composition api. I hope it will solve most of the vue/ts problems very soon. And hope it will be as intiitive and straight forward as vue framework itself.

octref commented 5 years ago

When using lang="ts", you should use export default Vue.extend({...}). Otherwise the error checking might not be accurate.

vertic4l commented 4 years ago

Or just stop using bullshit like Vuex which encourages you to use magic strings to access a getter of a store. Go for MobX.

And even better: Stop using VueJS. It's just garbage.