Skip to content

Update Vetur type inference for SFCs #1226

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

Merged
merged 2 commits into from
Oct 21, 2017

Conversation

ferdaber
Copy link
Contributor

The Typescript guide says that exporting Vue.extend({...}) will no longer be necessary in Typescript-based SFCs due to Vetur having correct syntax highlighting and type inference. Despite the fact that Vetur deals with this correctly without wrapping, the Typescript compiler will produce an error when the default export isn't wrapped, presumably because it does not make the same assumptions as Vetur.

The official Typescript Vue starter guide references this as well, stating that Vue.extend({...}) is still required even with Vetur.

This change is to remove that snippet in the Typescript guide so that users aren't confused that their Typescript compilers are erroring out despite Vetur working correctly.

@chrisvfritz chrisvfritz requested a review from octref October 19, 2017 00:39
@chrisvfritz
Copy link
Contributor

Happy to merge with approval from @octref.

@HerringtonDarkholme
Copy link
Member

I wonder under what situation TS would throw errors, since the typing definition we provide already accepts plain ComponentOptions.

@octref
Copy link
Member

octref commented Oct 19, 2017

@HerringtonDarkholme I guess he meant TS won't compile for

export default {
 ...
}

Is that true that there is no way to config TS to support it? I haven't used much TS + Vue in combination yet, and when I was testing I was always using Vue.extend in TS blocks.

@ferdaber
Copy link
Contributor Author

ferdaber commented Oct 19, 2017

@HerringtonDarkholme the two cases I found that created the error are:

Exporting a default object and later using that as a Vue constructor:

<script lang="ts">
// App.vue
export default {
  // ...
}
</script>
// index.ts
import App from './App.vue'
new App({
  el: '#app'
})

gives an error:

TS2351: Cannot use 'new' with an expression whose type lacks a call or construct signature.

Exporting a default object for a component that references this and then later importing that component:

<script lang="ts">
// Message.vue
export default {
  data() { return { message: 'Hello' } },
  methods: {
    clearMessage() { 
      this.message = '' // problematic
    }
  }
}
</script>
<script lang="ts">
// App.vue
import Message from './Message.vue'
// ...
</script>

gives an error:

TS2339: Property 'message' does not exist on type '{ clearMessage(): void; }'.

In general it looks consistent that exporting a default plain object leads Typescript to not infer (even from the 'vue-shim.d.ts' ambient module declaration) that the object itself is a Vue type. This is my module declaration FYI:

declare module '*.vue' {
    import Vue from 'vue'
    export default Vue
}

@HerringtonDarkholme
Copy link
Member

@ferdaber Yes, using this will break ts-loader compilation, because Vetur's wrapping only affects editor, not ts-loader.

Vue.extend seems to be required for ts-loader users for type checking. Only JS users or transpile-only TS users can benefit from Vetur's editing.

Maybe we can just remove the Vetur section? So TS users (I guess most of them do type check at ts-loader) will not be confused.

Is removing ok? @octref @chrisvfritz

@octref
Copy link
Member

octref commented Oct 20, 2017

I agree with removing. On the Vetur side we should separate TS mode from JS mode and stop the default wrapping in TS blocks, so that people wouldn't be "fooled" by Vetur.

That default wrapping is only meant for JS.

@ferdaber
Copy link
Contributor Author

Changed the file to remove the entirety of the Vetur section.

This is probably not the forum for this but I'm curious still as to why the TSC will still throw a compile time error when importing a .vue file and using it as a Vue constructor (see the App example above). I had thought that using the module shim allows TS to cast whatever is imported with a .vue extension as a Vue constructor?

@HerringtonDarkholme
Copy link
Member

Probably because ts-loader will read the script content in the vue file rather than reading from module declaration. This is ts-loader's feature.

If you encounter this without webpack and ts-loader, please let me know how you do that.

@ferdaber
Copy link
Contributor Author

Awesome, thanks for the clarification!

@chrisvfritz chrisvfritz merged commit b9f59cb into vuejs:master Oct 21, 2017
@ferdaber ferdaber deleted the update-typescript-guide branch October 21, 2017 02:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants