Skip to content

Boolean casting not working when using type-only props with generic components #13787

@larsrickert

Description

@larsrickert

Vue version

3.5.19

Link to minimal reproduction

https://play.vuejs.org/#__PROD__eNp9U8Fu1DAQ/ZWRxQGkKitUOBC2iwD1ABKlgj1aQt5kNuvi2JY9Trda9t8ZO026qtqeYs+8mXnP83IQn72vhoSiFsvYBO0JIlLyK2l1710g+Op6D9vgepCiWuRbxksh7XIxVjCWL4S9N4qQbwDLUuWD7jXpAeE2KO+xhT4Z0t4gNDts/nJgMcI34f70YwIo286guHPJtLBxtAPaIXgVI4dVBAoJYZMIVEBgAnQHkYK2XawyvxNO4kxQbJzd6q66ic6y4EMeKEXDVLXB8NOTdjZKUUPJ5Jwyxt1+L7E86myKF2ZPxG/iPsekuA4YMQz8TnOOVOiQxvTl7yvc83lO9q5NhtEvJH9hdCZljiPsS7It0z7BFbbfytr4Cdbxck9o4yQqE83IY8FLwVvMW3pO+gPd8+pdqZP2yK84OeDEMUbZ7oIruMHoHujQYtANB9fzRlkT2jbyGp1BxSKKb+jOI1wlY9TG4HK9ggtYwz+wHOEPS8Sttth+nLHXwfm4fLZtblA0zOarpxT3gMmJ9cPMqbCkJ4PWME8o8XsrnoTnwcWDn6YhUIPFAQNX8YNJy5aLxGSYNDMb1YwSHglZrV6/4aKXfqpWD+UAcDjAq7HnkadwajHmHlv+DzPJBuBlnVfvq7cfxPE/M/hbFg==

Steps to reproduce

Our specific issue is that when using generic components for defining props, the runtime prop type is missing and therefore the Boolean Casting doesn't work as expected.

  1. Define a generic component
<script lang="ts" setup generic="TMultiple extends boolean">

type Nullable<T> = T | null | undefined;

type Props<TMultiple extends boolean> = {
  primitive: boolean;
  wrapped: Nullable<boolean>;
  multiple: TMultiple;
  checked: TMultiple extends true ? boolean : never;
}

const props = defineProps<Props<TMultiple>>();
</script>

<template>
  <div>
    {{ $props }}
  </div>
</template>
  1. Use the boolean props
<template>
  <Comp primitive wrapped multiple checked />
</template>
  1. The resulting output for $props is:
{ "multiple": "", "checked": "", "primitive": true, "wrapped": true }
  1. The compiled runtime output is:

Note that the runtime prop types for multiple and checked are missing

const __sfc__ = /*@__PURE__*/_defineComponent({
  __name: 'Comp',
  props: {
    primitive: { type: Boolean },
    wrapped: { type: [Boolean, null] },
    multiple: {},
    checked: {}
  },
  setup(__props) {


const props = __props;

return (_ctx,_cache) => {
  return (_openBlock(), _createElementBlock("div", null, _toDisplayString(_ctx.$props), 1 /* TEXT */))
}
}

})

What is expected?

  • boolean casting should also work for the multiple and checked properties so true is passed as value
  • runtime prop types for multiple and checked are inferred correctly

What is actually happening?

  • runtime prop types for multiple and checked are missing
  • multiple and checked booleans are passed as empty strings instead of true boolean

System Info

System:
    OS: macOS 15.6
    CPU: (14) arm64 Apple M4 Max
    Memory: 394.27 MB / 36.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 22.15.0 - ~/.local/state/fnm_multishells/32954_1755762140665/bin/node
    npm: 10.9.2 - ~/.local/state/fnm_multishells/32954_1755762140665/bin/npm
    pnpm: 10.14.0 - /opt/homebrew/bin/pnpm
    bun: 1.2.20 - /opt/homebrew/bin/bun
  Browsers:
    Chrome: 139.0.7258.128
    Edge: 139.0.3405.102
    Safari: 18.6
  npmPackages:
    vue: ^3.5.19 => 3.5.19

Any additional comments?

In #12876 / #12872 the issue was fixed that boolean casting does not work when using wrapped generics (e.g. Nullable<boolean> as property type). The issue was fixed with version 3.5.19.

However, the issue still exists when using generic components as described above.

An example use case for this is a select / dropdown component that can either be single or multiselect that uses a generic TMultiple type for typing the modelValue property either as single value or as array.

Metadata

Metadata

Assignees

No one assigned

    Labels

    has workaroundA workaround has been found to avoid the problemscope: sfc

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions