Skip to content

toRefs type is wrong when using defineProps with optional boolean props #5847

Closed
@extrem7

Description

@extrem7

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

Activity

liulinboyi

liulinboyi commented on May 2, 2022

@liulinboyi
Member

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

StephenChips

StephenChips commented on May 3, 2022

@StephenChips
Contributor

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

liulinboyi

liulinboyi commented on May 3, 2022

@liulinboyi
Member

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.

StephenChips

StephenChips commented on May 4, 2022

@StephenChips
Contributor

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

extrem7

extrem7 commented on May 4, 2022

@extrem7
Author

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

ig1na

ig1na commented on Jun 14, 2022

@ig1na

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 ?

Guebbit

Guebbit commented on Aug 24, 2022

@Guebbit

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

added a commit that references this issue on Feb 2, 2023
a0a010d
added a commit that references this issue on Apr 12, 2023
aaff0a5
added a commit that references this issue on May 14, 2023
50ae243
locked and limited conversation to collaborators on Sep 15, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Participants

      @LinusBorg@Guebbit@ig1na@StephenChips@extrem7

      Issue actions

        toRefs type is wrong when using defineProps with optional boolean props · Issue #5847 · vuejs/core