Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't TypeScript recognize module augmentation for a Vue plugin?

I have a Vue project that I'm building to learn both Vue and TypeScript. The project has a chunk of static data that I've chosen to make available to components as a Vue plugin, adding a property to the Vue prototype.

import _Vue from 'vue';

export default function myPlugin(Vue: typeof _Vue): void {
  Vue.prototype.$myPlugin = { one: 1, two: 2 };
}

I followed the advice in a post by Peter Kuhn, defining the property type in a test-plugin.d.ts file.

import Vue from 'vue';

declare module 'vue/types/vue' {
    interface Vue {
        $myPlugin: object;
    }
}

Finally, I import and use() the plugin.

import Vue from 'vue';
import App from './App.vue';
import MyPlugin from './test-plugin';

Vue.use(MyPlugin);

new Vue({
  render: (h) => h(App),
}).$mount('#app');

However, when I reference the property in a single-file Vue component, both vscode and the TypeScript transpiler throw an error that the property doesn't exist.

<script lang="ts">
import Vue from 'vue';

export default Vue.extend({
  name: 'HelloWorld',
  props: {
    msg: String,
  },
  data: {
    one: 0,
  },
  created(): void {
    this.one = this.$myPlugin.one;
  },
});
</script>

The error:

ERROR in /Users/kccricket/Projects/what-the-heck/vue-plugin-test/src/components/HelloWorld.vue
43:21 Property '$myPlugin' does not exist on type 'CombinedVueInstance<Vue, { one: number; }, {}, {}, Readonly<{ msg: string; }>>'.
    41 |   },
    42 |   created(): void {
  > 43 |     this.one = this.$myPlugin.one;
       |                     ^
    44 |   },
    45 | });
    46 | </script>

Despite the error, this.one === 1 as I'd expect once the code is built and executed. Can anyone pinpoint what I'm doing wrong, here?

I've posted the sample code to GitHub: https://github.com/kccricket/what-the-heck/tree/master/vue-plugin-test

Environment

"dependencies": {
  "vue": "^2.5.16"
},
"devDependencies": {
  "@vue/cli-plugin-typescript": "^3.0.0-rc.5",
  "@vue/cli-service": "^3.0.0-rc.5",
  "vue-template-compiler": "^2.5.16"
}
like image 276
kccricket Avatar asked Jul 22 '18 22:07

kccricket


People also ask

Is Vue compatible with TypeScript?

Now, you should be able to get your Vue app up and running in TypeScript with features like defineComponent , data, props, computed properties, methods, and watchers. Vue 3.0 includes better support for TypeScript out of the box, and the entire Vue code was rewritten in TypeScript to improve maintainability.

How do I add TypeScript to an existing Vue project?

Actually, you can also implement TypeScript one file at the time with Vue (if you add it to an existing project). You take one of your Vue files and add the lang="ts" inside the script tag. Then you modify your component to use the Class API and fix the potential errors TypeScript found. It's really easy!


2 Answers

When you augment Vue typings for use with a plugin - as in test-plugin.d.ts - you need to import Vue first:

import Vue from 'vue'

declare module 'vue/types/vue' {
  interface Vue {
   $myPlugin: object 
  } 
}

Its explained here in the docs.

update

I don't see mention of it your post, but if you haven't done so you also need a shim for single file components:

// sfc.d.ts
declare module '*.vue' {
  import Vue from 'vue'
  export default Vue
}

You can see this in the TypeScript-Vue-Starter repository.

update

Disregard the above, I didn't notice the sample repo. I managed to resolve the type error, see the changes here.

answer

As noted by @kccricket, the plugin's implementation and declaration files were named the same, thus causing the module in resolve incorrectly.

// original file names

test-plugin.ts
test-plugin.d.ts
like image 146
Brian Lee Avatar answered Nov 08 '22 18:11

Brian Lee


what worked for me was to have the below declaration inside the .ts plugin file:

declare module 'vue/types/vue' {
  interface Vue {
    $myPlugin: object;
  }
}

i tried having the same thing in the .d.ts file as recommended in that article, but intellisense still couldn't see it properly in the component code.

like image 42
aragalie Avatar answered Nov 08 '22 18:11

aragalie