Vue: Null is not treated as Object in component prop check

Created on 4 Dec 2015  路  8Comments  路  Source: vuejs/vue

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.

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..

All 8 comments

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?
image

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

Dead Ends

// 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']
Was this page helpful?
0 / 5 - 0 ratings

Related issues

bfis picture bfis  路  3Comments

wufeng87 picture wufeng87  路  3Comments

fergaldoyle picture fergaldoyle  路  3Comments

bdedardel picture bdedardel  路  3Comments

paceband picture paceband  路  3Comments