nuxt / ui

A UI Library for Modern Web Apps, powered by Vue & Tailwind CSS.
https://ui.nuxt.com
MIT License
4.07k stars 525 forks source link

Provide proper types #731

Open some-user123 opened 1 year ago

some-user123 commented 1 year ago

Description

Components are not properly typed:

Cf: #668 #634

Additional context

No response

acidjazz commented 1 year ago

Found this issue looking at https://ui.nuxt.com/forms/form#backend-validation

I would love to be able to d something like

const form = ref<UForm|undefined>(undefined)
acidjazz commented 1 year ago

import type { Form } from '@nuxt/ui/dist/runtime/types/form'

const form = ref<Form<any>>()

@some-user123

some-user123 commented 1 year ago

My point is that the type exists, but is not correct. (form.value as any).submit() works. form.value.submit() causes a type error.

<UForm id="..."> works. But causes a type error if you enable vueCompilerOptions.strictTemplates.

The types don't match the actual implementation.

warrenseine commented 8 months ago

I stumbled upon this thread while searching how to import types and getting errors with the explicit import mentioned above:

error TS2307: Cannot find module '@nuxt/ui/dist/runtime/types' or its corresponding type declarations.

I wanted to mention that the (new?) way is:

import type { Form } from '#ui/types'
benjamincanac commented 1 week ago

@romhml Do you think all of these are fixed in v3? ๐Ÿค”

some-user123 commented 1 week ago

I'm not @romhml but I can comment, that so far I didn't find a similar issue in v3 ๐Ÿฅณ

However, it could be I've missed such an error as there are many other type errors (#2532 and #2536).

some-user123 commented 1 week ago

I just found one issue ๐Ÿคจ:

<UInput @input="onInput" />

works, but causes a type error

[vue-tsc] Object literal may only specify known properties, and 'onInput' does not exist in type 'NonNullable<{ readonly modelValue?: string | number | undefined; readonly id?: string | undefined; readonly name?: string | undefined; readonly type?: InputTypeHTMLAttribute | undefined; ... 22 more ...; readonly "onUpdate:modelValue"?: ((value: string | number) => any) | undefined; } & VNodeProps & AllowedComponent...'.

But still, v3 is a huge improvement and really makes me consider @nuxt/ui again. ๐Ÿ‘

some-user123 commented 1 week ago

Found another one:

<UInput type="submit" form="ref" />

works, but fails type check:

Object literal may only specify known properties, and 'form' does not exist in type 'Partial<{}> & Omit<{ readonly disabled?: boolean | undefined; readonly icon?: string | undefined; readonly variant?: "link" | "solid" | "outline" | "soft" | "subtle" | "ghost" | undefined; ... 36 more ...; readonly loadingIcon?: string | undefined; } & VNodeProps & AllowedComponentProps & ComponentCustomProps, never>'.

romhml commented 6 days ago

I could not reproduce any type issues mentioned except for the Form component using the v3 branch and useTemplateRef . I submitted a fix for the form component which types the $el attribute in order to access the form element attributes without typing errors.

benjamincanac commented 5 days ago

@some-user123 Could you summarize what exactly doesn't work? I couldn't reproduce the last two examples you sent.

I'd like to close this if everything's fine ๐Ÿ˜Š

some-user123 commented 5 days ago

I think, this should be a minimal reproduction: https://github.com/some-user123/nuxt-ui-issue731.

If you run npx nuxi typecheck on it:

app.vue:2:12 - error TS2353: Object literal may only specify known properties, and 'onInput' does not exist in type 'NonNullable<{ readonly modelValue?: string | number | undefined; readonly id?: string | undefined; readonly name?: string | undefined; readonly type?: InputTypeHTMLAttribute | undefined; ... 22 more ...; readonly onBlur?: ((event: FocusEvent) => any) | undefined; } & VNodeProps & AllowedComponentProps & ComponentCus...'.

2   <UInput @input="() => console.log('hi')"></UInput>
             ~~~~~

app.vue:3:26 - error TS2353: Object literal may only specify known properties, and 'form' does not exist in type '{ readonly label?: string | undefined; readonly color?: "error" | "primary" | "secondary" | "success" | "info" | "warning" | "neutral" | undefined; readonly variant?: "link" | "solid" | ... 4 more ... | undefined; ... 36 more ...; readonly inactiveClass?: string | undefined; } & VNodeProps & AllowedComponentProps & ...'.

3   <UButton type="submit" form="ref">Hello</UButton>
                           ~~~~

If you disable strictTemplates in tsconfig.json (which I would consider bad practice), you can avoid these type errors , but you also don't get any hints that these properties are available: Image Image

Nor do you get errors if you use these properties wrongly, e.g.

  <UInput @input="123">Hello</UInput>
  <UButton type="submit" :form="() => console.log('foo')" />

Does this help?

benjamincanac commented 5 days ago

So this is related to strictTemplates (nuxt/ui#2562) and we can close this?

some-user123 commented 5 days ago

No, these are separate issues. #2562 is that already the pure installation of @nuxt/ui (without using any component of it) causes type errors when strictTemplates is enabled.

This issue is that @nuxt/ui components are not properly typed. More specifically some properties are missing, e.g. form of UButton and @input of UInput. This problem manifests itself in different ways:

benjamincanac commented 5 days ago

There are thousands of possible props on the <input> element. There is no way we can type them all: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attributes

It's the same about events, what do you need the @input for in the first place? Why not use v-model or @update:model-value or even @change? ๐Ÿค”

https://ui3.nuxt.dev/components/input#emits

some-user123 commented 5 days ago

There are thousands of possible props on the <input> element. There is no way we can type them all: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input#attributes

<input> elements are properly typed as HTMLInputElement. I don't think you need to re-invent the wheel. If UInput accepts the same parameters, you can inherit those. Types are available in vue, e.g. InputHTMLAttributes (https://github.com/vuejs/core/blob/76c43c6040518c93b41f60a28b224f967c007fdf/packages/runtime-dom/src/jsx.ts#L518). I don't think you should hardcode all of them...

what do you need the @input for in the first place? Why not use v-model or @update:model-value or even @change? ๐Ÿค”

Both @change and @update:model-value have a different signature and don't provide the actual event as parameter like @input does. Of course there are always ways around it. Ultimately, I could build my own component that wraps <input>, but that's the whole point of using a library, making live easier, not harder...

If I already have full type support on <input> incl. error checks and IDE support, I'd hope to get the same (and some more) from <UInput>.

In PrimeVue (as an example), I not only get the types right, but also the full description: Image