docs icon indicating copy to clipboard operation
docs copied to clipboard

Custom plugin in Typescript after Vue 3.4 update

Open joaoefornazari opened this issue 1 year ago β€’ 12 comments

According to Vue 3.4 docs, if I want to define a custom plugin, I need to create it like this:

// my-custom-plugin.ts
export default {
  install: (app, options) => {
    // do something here with app and options
  }
}

Then, on main.ts, I set app to use it:

import App from './App.vue'
import router from './router'
import customPlugin from './my-custom-plugin'

export const app = createApp(App)
app.use(router)
app.use(customPlugin)

And that was OK until I updated Vue to version 3.4.20. I was using 3.2.45 before.

Now, when I try to build the project with yarn build (which uses vite build too) it throws this error:

Argument of type '{ install: (app: App, options: any) => void; }' is not assignable to parameter of type 'Plugin<[]>'.
  Type '{ install: (app: App, options: any) => void; }' is not assignable to type 'FunctionPlugin<[]>'.

After searching for type definitiions in node_modules/@vue/runtime-core/dist/runtime-core.d.ts, I found out that, in order to Typescript doesn't claim any type errors, I must define my plugin as an ObjectPlugin type.

I did it this way:

import { ObjectPlugin } from 'node_modules/@vue/runtime-core/dist/runtime-core'

export default {
  install: (app, options) => {
    // stuff
  },
} as ObjectPlugin

I can't use Plugin type because it says that Plugin type is deprecated.

Is my fix correct? How can I contribute so the Vue docs has some notes regarding Typescript support?

joaoefornazari avatar Mar 04 '24 15:03 joaoefornazari

@joaoefornazari have you reached the issue on the core repository? It looks like we might improve the code instead of adding a specific section to docs πŸ€”

NataliaTepluhina avatar Mar 27 '24 12:03 NataliaTepluhina

@NataliaTepluhina I'll give a try. This is a thing that never happened to me so I was lost in what to do about it - I thought that there was already something on Vue core that would solve this but people forgot to put it on the docs. That's why I opened the issue.

Maybe I open an issue on vuejs/core? What would you recommend?

joaoefornazari avatar Mar 27 '24 17:03 joaoefornazari

I can't use Plugin type because it says that Plugin type is deprecated.

Where? There is no deprecation notice for that (https://github.com/vuejs/core/blob/01172fdb777f9a0b51781ed2015a1ba3824340a3/packages/runtime-core/src/apiCreateApp.ts#L168). import type { Plugin } from 'vue' should work fine. Also you should not cast it to Plugin, it should be satisfies Plugin:

import type { Plugin } from 'vue'

export default {
  install(app, options) {

  }
} satisfies Plugin

// or if you're using named exports

export const foo: Plugin = {
  install(app, options) {

  }
}

brc-dd avatar Mar 27 '24 17:03 brc-dd

I solved the problem that happened with me here.

I did it like this:

  • my-custom-plugin.ts
// using import { PluginOptions } from 'unocss' also work
import { App, Plugin } from 'vue'

export default {
  install: (app: App, options?: any) => {
    // stuff using app and options (optional)
  },
} satisfies Plugin
  • main.ts
import App from './App.vue'
import router from './router'
import customPlugin from './my-custom-plugin'

export const app = createApp(App)
app.use(router)
app.use(customPlugin)

Thanks @brc-dd for the clarification! But still, this solution ain't listed on the docs. @NataliaTepluhina Shouldn't it be there?

joaoefornazari avatar Mar 27 '24 20:03 joaoefornazari

I have the exact same problem and the above solution did not work for me. I am using Vue version 3.4.26. I am creating a component library. The plugin works fine when I use it directly in my component library, but when I export the plugin and try to use it in another project it throws these errors:

Argument of type '{ install: (app: App<any>) => void; }' is not assignable to parameter of type 'Plugin<[]>'.
  Type '{ install: (app: App<any>) => void; }' is not assignable to type 'FunctionPlugin<[]>'.
    Type '{ install: (app: App<any>) => void; }' is not assignable to type '(app: App<any>) => any'.
      Type '{ install: (app: App<any>) => void; }' provides no match for the signature '(app: App<any>): any'.ts(2345)

os-tohe avatar May 08 '24 08:05 os-tohe

I had this issue with v3.4.16, but upgrading to v3.4.29 resolved it.

chriscdn avatar Jun 21 '24 08:06 chriscdn

I'm also seeing this error when bumping to vue version ^3.4.30. Most recent working version is 3.4.25 - Variations of the solutions above do not resolve the problem.

dmoczisko avatar Jun 25 '24 16:06 dmoczisko

Do any of you have a minimal, reproducible example? Also the code in https://github.com/vuejs/docs/issues/2729#issuecomment-2023953841 is not exactly correct, if you're saying something satisfies Plugin, you don't need type parameters on individual arguments, certainly not two commas and any.

Also it doesn't seem like a docs issue. If you're not able to make something work, a better place to ask might be on https://chat.vuejs.org. In the docs, we can just add a short sub section at https://vuejs.org/guide/reusability/plugins.html#writing-a-plugin showing how to use it with typescript. Basically, something like the equivalent of JS example there:

// plugins/i18n.ts
import type { Plugin } from 'vue'

export default {
  install: (app, options) => {
    // Plugin code goes here
  }
} satisfies Plugin

brc-dd avatar Jun 25 '24 16:06 brc-dd

@brc-dd Oh, sorry. I didn't see the comma lost over there. Also, the comma is not on my original code, so no problem at all - but I'll fix the code on the comment.

And also: adding a short subsection on the Writing a Plugin page would be good IMO. I really like how Vue docs takes care of mentioning Typescript typing when it is the case. The Vue docs is one of the easiest and "straightforward-est" docs to read out there, so it really surprised me to discover that I had to find out the correct Typescript approach by myself. I know this situation can sound simple, but it wasn't obvious to me and apparently it wasn't for some other people too.

EDIT: Code fixed.

joaoefornazari avatar Jun 26 '24 01:06 joaoefornazari

Yeah regarding docs I agree. But the last three comments are probably because of something else. They better be posted on discussions/discord. One is saying it works with v3.4.29 and the other is saying that most recent working version is v3.4.25 -- which are obviously conflicting. If any of those can share a repo where this happens we could probably resolve those.

brc-dd avatar Jun 26 '24 03:06 brc-dd

In my particular case, this issue was as a result of a mismatch in package.json files both referencing vue, but with different versions

dmoczisko avatar Jun 27 '24 15:06 dmoczisko

I meet the same problem with v3.4.29 ,but upgrading to v3.4.30 resolved it。by the way, before I upgrading to v3.4.30, I delete the node_modules and pnpm-lock.yaml, then I reinstall the project by pnpm i , maybe this also help πŸ˜„

luckylark2000 avatar Jun 30 '24 10:06 luckylark2000