vuejs / core

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

`undefined` type in prop could warn #5471

Open livthomas opened 2 years ago

livthomas commented 2 years ago

Version

3.2.31

Reproduction link

sfc.vuejs.org/

Steps to reproduce

  1. Define a prop with type number | undefined using defineProps function
  2. Try to pass undefined value to this prop
  3. Look at the warning in the dev console

What is expected?

If you define prop type as number | undefined, there should be no warning if you pass undefined value.

What is actually happening?

Vue somehow interprets the type definition as number | null and complains about undefined not matching this type:

[Vue warn]: Invalid prop: type check failed for prop "count". Expected Number | Null, got Undefined

Of course you can use defineProps<{count?: number}>(). But this definition doesn't make the prop required and so an IDE won't warn you if you forget to pass in the value. I want to force all consumers of my component to provide count prop while still being able to pass undefined as a valid value.

posva commented 2 years ago

The type could be number | null but not number | undefined. undefined is meant for non-defined values, so if you want to be able to pass undefined, you must set your prop as optional. To pass a "non-existant" value, pass null instead.

If you still want to have your way of handling undefined, you can pass a custom validator and type: null to accept anything:

defineProps({ count: {
  type: null,
  validator: v => v === undefined || typeof v === 'number',
  required: true,
}});
livthomas commented 2 years ago

It could be number | null if I had control over the data that is coming in but I don't. It comes from the API and the field is either present there or not (in which case the value is undefined).

I don't want to put :count="count ?? null" everywhere just because Vue cannot handle undefined. I will rather make the prop optional to get rid of the warning even though the value always needs to be provided.

It would be nice if Vue at least didn't show such misleading warnings.If you cannot make it work as expected, then at least don't change the type from number | undefined to number | null under the hood. It's very confusing. You should rather treat such props as optional if there is no other viable solution.

loilo commented 2 years ago

To pass a "non-existant" value, pass null instead.

Thank you for the clarification @posva!

It would be nice if Vue at least didn't show such misleading warnings.

I second this. That number | undefined is not possible doesn't really bug me, but the error message mislead me into thinking this was a compiler error on Vue's side instead of a comprehension problem on my side, and it took me quite some time to find this issue.

akhma-ps commented 1 year ago

Found a workaround. If you want to get rid of the annoying warning, you can specify the type you want, not directly, but through a generic, for example.

type AvoidValidation<T> = T

defineProps<{
  modelValue: AvoidValidation<string | undefined>
}>()

This is type-check friendly, you keep the ability to specify the field required. But you sacrifice the default property validation.