Subscribe on changes!

toRefs type is wrong when using defineProps with optional boolean props

avatar
May 2nd 2022

Version

3.2.26

Reproduction link

stackblitz.com

Steps to reproduce

import { toRefs } from 'vue'

const props = defineProps<{
  isLive?: boolean
}>()

const { isLive } = toRefs(props)

What is expected?

According to fix(runtime-core): ensure declare prop keys are always present type of isLive should be:

Ref<boolean>

What is actually happening?

The type of isLive actually is:

Ref<boolean | undefined> | undefined

isLive couldn't be undefined in no case

avatar
May 2nd 2022

In this test case if the props type is Boolean, absent should cast to false.

avatar
May 3rd 2022

Interesting, I tend to think this is a bug, since other primitive type's default value is undefined.

avatar
May 3rd 2022

Interesting, I tend to think this is a bug, since other primitive type's default value is undefined.

If it's a bug,it's easy to fix,change the handling of this situation

    // boolean casting
    if (opt[BooleanFlags.shouldCast]) {
      if (isAbsent && !hasDefault) {
        value = false
      } else if (
        opt[BooleanFlags.shouldCastTrue] &&
        (value === '' || value === hyphenate(key))
      ) {
        value = true
      }
    }

to

    // boolean casting
    if (opt[BooleanFlags.shouldCast]) {
      if (isAbsent && !hasDefault) {
        value = undefined
      } else if (
        opt[BooleanFlags.shouldCastTrue] &&
        (value === '' || value === hyphenate(key))
      ) {
        value = true
      }
    }

but in this test case if the props type is Boolean, absent should cast to false.

avatar
May 4th 2022

@liulinboyi

If is a not a bug, why we need this behaviour, what is the motivation of this design? It is kind of odd and inconsistent to other types. IMO, absent value should always be undefined.

I noticed that only boolean props will do the casting, other types will just remain undefined (e.g. number, string).

avatar
May 4th 2022

@StephenChips I think there are two different moments: Ref<boolean | undefined> and Ref<> | undefined. Seems like the second has no sense (because keys are always present in props). The first case may be consistent behavior.

avatar
Jun 14th 2022

Even when using withDefaults setting the prop to undefined, the type becomes Ref<boolean> but should be Ref<boolean | undefined>

Is there any workaround to use watchers on props without using toRefs ?

avatar
Aug 24th 2022

The problem is still there, I thought it was a little ugly to put an additional check, hope it will be fixed soon