I have a component that let's user select an object from an array.
<comp :selected.sync="selectedObject">
// parent data
data: {
selectedObject: null
}
// comp prop
props: {
selected: {twoWay: true, type: Object}
}
and in parent template I have something like
<div v-if="selectedObject"> blah blah blah </div>
<div v-else> please select an object </div>
which displays different content based on whether an object is selected.
and I get
[Vue warn]: Invalid prop: type check failed for selected="selectedObject". Expected Object, got Null.
I know i can just remove the "type: Object" check and suppress the warning,
but wouldn't it be better if component props checks treat null as an object?
Because javascript does that (typeof null === 'object'),
and setting null as an initial value (to my knowledge) doesn't affect mutation observation.
It fails because null
is not an Object... the typeof
behavior is commonly considered a bad design in the JavaScript language itself.
Just initialize it to an empty object.
Initializing with an {} will cause it to evaluate to true.. which means I won't be able to use v-if="selectedObject"
and I'll have to create another variable to store whether an object is selected.
I'll just remove the type check then..
@fnlctrl you just need to change it to v-if="Object.keys(selectedObj).length > 0"
@fnlctrl Which is a workaround, where either using such an exaggerated expression in template or writing a getter for each object to check if it is initialized seems not right.
Using Typescript with Vue complicates this even more, as one has to denote all objects as Partial<T>
or T | {}
for this approach to work.
What is the status of this issue in upcoming 3.0 release?
So, this any type in documentation is not actually any type?
When using Typescript, I have no way to specify string | null
.
My use-case is a filter that sets the value to null when cleared.
I know the workaround is to transform the null value to a string
before sending the prop to the component, but I _should not have to do that_.
Ideally, one of these would be the syntax:
{type: [Null,String] as () => string | null}
{type: Any as () => string | null}
{type: [Object,String] as () => string | null} // with null considered an object
// This will not work because 'Null' is not a type
{type: [Null,String] as () => string | null}
// This will not work because 'Any' is not a type
{type: Any as () => string | null}
// This will not work because null is not considered an Object, although is should be
{type: [Object,String] as () => string | null}
// This will not work because string is not considered an Object
{type: Object as () => string | null}
So I end up doing this, and the Typescript value is now undefined instead of string | null
js
{
validator: prop => typeof prop === 'string' || prop === null,
required: true,
}
@Flamenco
I am using some kind of workaround:
props: {
status: {
type: String as PropType<SomeType | null>,
default: null
}
}
The typescript compiler understand this.status
as SomeType
or null
however vue doen't have problems with passing null via prop.
I know people didn't like the first answer https://github.com/vuejs/vue/issues/1961#issuecomment-162007987 but this is not so bad actually : when calling your component, you can fill your prop this way, to make sure this is an object:
<CoachingSidebarCheckout :coaching="coaching ? coaching : {}" />
And then in your component, you can use a custom function like "isEmptyObject" (https://stackoverflow.com/questions/679915/how-do-i-test-for-an-empty-javascript-object?answertab=votes#tab-top) or use _.isEmpty({})
from lodash
<template v-if="!isEmptyObject(coaching)"> ...
At least your components props type declaration still makes sense
props: {
coaching: {
type: Object,
required: true
}
},
Allowing "null" leads to strange declaration, where a prop might be "required" but a "null" value is accepted...
props: {
coaching: {
type: null, // will accept also an object
required: true
}
},
At the end, you can also bypass type validation and just declare props this way :
props:: ['coaching']
Most helpful comment
Initializing with an {} will cause it to evaluate to true.. which means I won't be able to use
v-if="selectedObject"
and I'll have to create another variable to store whether an object is selected.I'll just remove the type check then..