vuejs / core

🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
https://vuejs.org/
MIT License
47.57k stars 8.31k forks source link

Properly typing web component created via defineCustomElement #9691

Open GabrielHangor opened 11 months ago

GabrielHangor commented 11 months ago

Vue version

3.3.4

Link to minimal reproduction

https://stackblitz.com/edit/vue3-vite-typescript-starter-juvyz7?file=src%2FApp.vue

Steps to reproduce

Using volar, if you hover over registered test-component (being a custom element) hints and strict types are only working if you manually cast the custom element to an original vue component (using the globals in components.d.ts).

What is expected?

Result of the defineCustomElement should be able to be direcly assigned as a type and template should provide correct typehints via volar.

What is actually happening?

So i have a need to use custom elements built via vue3 in our legacy vue 2, and for that purpose i decided to use defineCustomElement feature which is working great overall but typings are a bit odd or maybe i dont know how to better approach this.

Right now, if i try to declare globals using the result of the defineCustomElement, there is no autocomplete and type hints in the template. I have to directly use the original vue component which in my opinion is a bit odd. Is there a way to better approach this problem?

Other questiong is how to properly deal with the events. Right now, i've come up with this solution: const emit = defineEmits<{ (event: "update:selectedOption", value: CustomEvent<[string]>): void }>(); which is also suboptimal in my opinion.

Thank you.

System Info

No response

Any additional comments?

No response

pikax commented 11 months ago

@GabrielHangor it seems to be working, I've pulled your example and ran locally and seems to work image

steps

> download the project
> `pnpm i`
> change `selectedOption` to number on App.vue

Playground it should error, but is not.

This is most likely caused by language tools instead of vue/core.


Other questiong is how to properly deal with the events. Right now, i've come up with this solution: const emit = defineEmits<{ (event: "update:selectedOption", value: CustomEvent<[string]>): void }>(); which is also suboptimal in my opinion.

You can use object based

const emit = defineEmits({
  'update:SelectedOption': (value: CustomEvent<[string]>) => true
})

or prop based:

defineProps<{
  selectedOption: string,
  'onUpdate:SelectedOption': (value: CustomEvent<[string]>) => void
}>
GabrielHangor commented 11 months ago

@pikax Hey Carlos, My example is working since i casted the type of the custom element to the original vue component and declared it globally (in components.d.ts). This way typechecking and hints are working exactly as expected.

But the problem is that if you cast the custom element to the custom element in GlobalComponents interface, there are no hints. So, typeof defineCustomElement(...someElement) is not suitable to be used to type it in GlobalComponents, as shown in docs...

Hope that ive explained it clearly now.

As for the second question, many thanks, sounds neat.

GabrielHangor commented 11 months ago

I've found a solution, you just have to do it like that:

image

Now the types can be properly obtained by volar Maybe this should be added to the docs as an example because the current one is not correct...

GabrielHangor commented 11 months ago

Can make a PR...