Subscribe on changes!

Add ability to define required nullable props

avatar
Jun 13th 2021

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.

  1. 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.
  2. 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.
  3. 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' image (1)

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:

  1. Adding null to the list of possible type 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,
  }
}
  1. Adding nullable option to the prop object (https://v3.vuejs.org/api/options-data.html#props):
props: {
  category: {
    type: String,
    required: true,
    nullable: true,
  }
}
avatar
Jun 14th 2021

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,
    }
Screenshot 2021-06-14 at 09 39 22

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)

avatar
Jun 14th 2021

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

avatar
Jun 15th 2021

@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:

  1. type is used for defining the Type of values the property should accept
  2. null 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?

avatar
Aug 26th 2022

@posva saved my day! thanks mate!

this issue went quite stale. any progress on that in sight ?

avatar
Mar 9th 2023

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 by default: 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. The default: null solution is breaking this rule because the real default value is not coming from my state, but from the component itself...

avatar
Mar 9th 2023

bump

avatar
May 23rd 2023

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.

avatar
Jun 1st 2023

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>

avatar
Jun 12th 2023

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
  }
})
avatar
Jan 27th 2024

How about this proposed syntax:

props: {
  category: {
    type: String,
    nullable: true,
    required: false,
  }
},