Skip to content
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

Custom plugin in Typescript after Vue 3.4 update #2729

Open
joaoefornazari opened this issue Mar 4, 2024 · 12 comments
Open

Custom plugin in Typescript after Vue 3.4 update #2729

joaoefornazari opened this issue Mar 4, 2024 · 12 comments
Labels
content Issues / PRs related to docs content contribution welcome

Comments

@joaoefornazari
Copy link

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?

@NataliaTepluhina
Copy link
Member

@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 🤔

@joaoefornazari
Copy link
Author

joaoefornazari commented Mar 27, 2024

@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?

@brc-dd
Copy link
Member

brc-dd commented Mar 27, 2024

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) {

  }
}

@joaoefornazari
Copy link
Author

joaoefornazari commented Mar 27, 2024

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?

@bencodezen bencodezen added the content Issues / PRs related to docs content label Apr 25, 2024
@os-tohe
Copy link

os-tohe commented May 8, 2024

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)

@chriscdn
Copy link

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

@dmoczisko
Copy link

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.

@brc-dd
Copy link
Member

brc-dd commented Jun 25, 2024

Do any of you have a minimal, reproducible example? Also the code in #2729 (comment) 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

@joaoefornazari
Copy link
Author

joaoefornazari commented Jun 26, 2024

@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.

@brc-dd
Copy link
Member

brc-dd commented Jun 26, 2024

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.

@dmoczisko
Copy link

dmoczisko commented Jun 27, 2024

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

@luckylark2000
Copy link

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 😄

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
content Issues / PRs related to docs content contribution welcome
Projects
None yet
Development

No branches or pull requests

8 participants