Add ability to define required nullable props
What problem does this feature solve?
I haven't found a way to properly define required nullable props.
Why
I want to be able to define a component property that is required
and accepts null
as a value (along with "normal" types like String, Number, etc.)
I consider null
as a value, which indicates an absence of a value.
undefined
means the value is unknown (e.g. we don't know it yet because we haven't got a response from API request).
Hence, null
and undefined
should not be treated the same.
Problems with current workarounds
1. Marking the property as optional.
- If there is a bug in the code and a parent component does not specify the property at all, then I won't get any warnings from Vue.
- If there is a bug in the code and a parent component provides
undefined
as a value, then I won't get any warnings from Vue. - Typescript complains about the following code
props: {
category: {
type: String,
required: false,
}
},
setup(props) {
const { category } = toRefs(props);
console.log(category.value)
because TS considers category
as possibly 'undefined'
2. Mark the prop as required and hint TS about possible values
props: {
category: {
type: String as () => string | null,
required: true,
}
}
I get Vue warnings in the console "[Vue warn]: Invalid prop: type check failed for prop “category”. Expected String with value “null”, got Null"
What does the proposed API look like?
I have 2 ideas:
- Adding
null
to the list of possibletype
values https://v3.vuejs.org/guide/component-props.html#type-checks
So that I can define the prop the following way:
props: {
category: {
type: [String, null],
required: true,
}
}
- Adding
nullable
option to the prop object (https://v3.vuejs.org/api/options-data.html#props):
props: {
category: {
type: String,
required: true,
nullable: true,
}
}
You can use a validator
: (v: any) => typeof v === 'string' || v === null
and remove the type
:
category: {
required: true,
type: null as unknown as PropType<string | null>,
validator: (v: any) => typeof v === 'string' || v === null,
}
I'm not sure this is the intended way. It's probably worth adding this to docs.
I opened this PR https://github.com/vuejs/vue/pull/9358/files for Vue 2 but we didn't get anywhere with it. I personally would prefer being able to do type: [String, null]
but as pointed out here it does create an inconsistency with type: null
which currently allows anything (as allowing a prop only when it's null
makes no sense)
type: null
which currently allows anything (as allowing a prop only when it's null makes no sense)
On the other hand [whatever, null]
doesn't make sense as well, if null
means "anything" then adding other types to the array is pointless. And because of that it's very unlikely that it would be a breaking change for anyone
@posva Thank you a lot for the workaround 👍 I didn't know I can set type
to null
. It gives me what I wanted to achieve.
Yet, having built-in support for that would of course be nice!
Ok, I see the problem with [whatever, null]
as null
is already used and has a different meaning.
Then what about the second variant:
props: {
myProp: {
type: String,
required: true,
nullable: true,
}
}
To me, it kinda makes sense:
type
is used for defining the Type of values the property should acceptnull
is used to denote the absence of a value, hence it's better not to treat it as a separate type, but rather as an enhancement of any other type.
Pros/cons for nullable
?
Up, this issue is really annoying for the code readability and maintainability. We have two options for now :
use
type: null as unknown as PropType<string | null>,
which is hard to read and sounds wrong, because the real prop type is a string but nullable.do not use
required: true
and replace it bydefault: null
, which create a change between the developer needs and what the code is doing in reality. For example, i use a state management library, a component is listening a property from that state and passing it to a child component. I want to set the default value to null in my state, because the state should be my single source of truth. Thedefault: null
solution is breaking this rule because the real default value is not coming from my state, but from the component itself...
Facing this problem as well, the database/json definitely have a lot of null, so I think ability to make a props type nullable is quite important
type: null as unknown as PropType<string | null>
is my current workaround for my component.
I use Quasar, they export another type definition to make string | null | undefined
possible.
The current work around is a bit silly but the only way to remove all the warnings etc. Would it be worthwhile having another PropType primitive like NullablePropType? such as type: Object as NullablePropType<MyType>
instead of writing type: null as unknown as Object as PropType<MyType|null>
ATM, we can try the solution below. It has type validation and absent checking.
For <script setup lang="ts">
const props = defineProps({
msg: {
type: [Boolean, null] as PropType<boolean | null>,
required: true
}
})
// or using type declaration
const props = defineProps<{
msg: boolean | null
}>()
props.msg
// ^ boolean | null
TS:
defineComponent({
props: {
msg: {
type: [Boolean, null] as PropType<boolean | null>,
required: true
}
},
setup(props) {
props.msg
// ^ boolean | null
}
})