kccricket
kccricket

Reputation: 223

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"
}

Upvotes: 12

Views: 12722

Answers (2)

Brian Lee
Brian Lee

Reputation: 18197

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

Upvotes: 12

aragalie
aragalie

Reputation: 195

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.

Upvotes: 7

Related Questions