Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prop type inference for typeof Symbol() is incorrect and breaks Vue runtime checks #12234

Open
JoCa96 opened this issue Oct 22, 2024 · 0 comments · May be fixed by #12240
Open

Prop type inference for typeof Symbol() is incorrect and breaks Vue runtime checks #12234

JoCa96 opened this issue Oct 22, 2024 · 0 comments · May be fixed by #12240

Comments

@JoCa96
Copy link

JoCa96 commented Oct 22, 2024

Vue version

3.5.12

Link to minimal reproduction

https://play.vuejs.org/#eNp9UsluwjAQ/RXLJyqhoJb2AoGqC4dWaosKR0uVCRMIdWzLdlhE8+8dO5Ag1HKyZ96bmTfLnj5oHa0LoD0a28Rk2hELrtBDJrNcK+PIk8o1SY3KCaNRx1uez2ifybhThSAZDQe5FtwBWoTEIayD/7hTA7RNnU2UTLNFtLJKYtG9JzOaIDsTYD60y5S0jPZIQDzGhVCb1+BzpoD20Z8sIfn+w7+yW+9jdGzAglmj1hpz3CzAVfBo8g5b/NdgruaFQPYF8BOsEoXXWNEeCzlH2Se8oPYljC6Ti6kdbR1Ie2zKC/XMMvAZxUn6Qf3XeiO3G92GOCZLnOJxC+dbI4LLxQDjME2zwT152012+UyJNqne6U4DKZut8rBOJjeZWz5DygvhbGsOaSZhbJS2cVC05qKA+95pjh8yU0oAlxheDltXbSwWaL26JimvLp+KATkHY88vhUfOYn+wDT3g1VjX5BwcRLR87gPFeUEn2gbBo9I6qo9Zv9ZYCueMmbvRXXR9Q8tfnZgErg==

Steps to reproduce

  1. Export a symbol in a typescript file a.ts
// a.ts
export const MySmbol = Symbol();
  1. In a Vue file Comp.vue with <script setup lang="ts"> import and use the symbol as prop type and default:
  2. Update the prop type to be a union of the symbol type and some other inferable type, e.g., boolean.
  3. Use the symbol as default value:
// Comp.vue
<script setup lang="ts">
import { MySmbol } from "./a";

withDefaults(defineProps<{
  value?: typeof MySmbol | boolean;
}>(), { value: MySymbol });
</script>

<template>
  renders
</template>

==> Check the JS output, and you can see that only the boolean type of the type union is inferred:

 props: {
    value: { type: [Boolean], default: MySymbol }
  },
  1. Switch to Prod mode
  2. Create a second component, import and use the first component:
// App.vue
<script setup>
import Comp from "./Comp.vue";
</script>

<template>
  <Comp />
</template>
  1. Switch to DEV mode.
    ==> Now you will get the error: can't convert symbol to string

Why is the DEV mode switching relevant?
We are building a component library and there we use symbols as explicit defaults for special default behaviors.
This issue was only encountered when a user tried to develop (in dev mode) using the compiled lib (in prod mode).

See also: SchwarzIT/onyx#1980 (comment)

What is expected?

  • The symbol type should be inferred correctly or no runtime check at all should be happening:
 props: {
    value: { type: [Symbol, Boolean], default: MySymbol }
  },

or

props: {
    value: { default: SYMBOL }
  },
  • No error when a (PROD) compiled component is used for development

What is actually happening?

Vue's compiler inferred the prop type used for runtime validation as Boolean, even though the typescript type is typeof unique symbol | boolean. This causes the runtime validation to fail and trying to log an error. Because Vue tries to create an error message using implicit string conversions and symbols cannot be implicitly converted to a string, the JS runtime throws: Uncaught (in promise) TypeError: can't convert symbol to string

System Info

System:
    OS: macOS 13.6.7
    CPU: (10) arm64 Apple M1 Max
    Memory: 81.38 MB / 32.00 GB
    Shell: 5.9 - /bin/zsh
  Binaries:
    Node: 20.17.0 - ~/Library/Caches/fnm_multishells/37685_1729492712079/bin/node
    Yarn: 3.4.1 - ~/Library/Caches/fnm_multishells/37685_1729492712079/bin/yarn
    npm: 10.8.2 - ~/Library/Caches/fnm_multishells/37685_1729492712079/bin/npm
    pnpm: 9.7.1 - ~/Library/Caches/fnm_multishells/37685_1729492712079/bin/pnpm
    bun: 1.1.21 - ~/.bun/bin/bun
  Browsers:
    Brave Browser: 122.1.63.169
    Edge: 130.0.2849.46
    Safari: 17.5

Any additional comments?

We try to use symbols as explicit defaults in place of undefined, because the implicit default for boolean is false.

You can find playground examples with different usages of unique symbols here:
https://play.vuejs.org/#__PROD__eNp9Ul1LwzAU/SuXPCmMil8vc06c+KA4J24gQkBqezuraRKSdHbM/Xdv0nbWKXtqcs+5t+eenBW71DpalMj6bGATk2sHFl2pQcRyfs6Zs5wNucwLrYyDFUyfx6PJXQ+my+JViQejdHuemJFSAmPZgycTa40G1pAZVQBn0YEmJo0645LLFLNcou+1gxWXAPV0TGdLjZOsHnfR7/yD2gCUFMsthqOryhpRgVTkVTtnG4cveK0VBmb70/Gvjq1dAvMzrJMS2iw2aOYMCV4P9/bpMzio3SOv6OKw0CJ2SDcAg7SxsZ7TqbMeeZsomeXz6N0qSQ8QvOAsUYXOBZqJdrmSZFofAuKxWAj1eRtqzpTYa+vJGyYf/9TfbeVrnD0YtGgWyNkGc7GZo6vh6+k9VnTegIVKS0HsHeAjWiVKr7GmjUqZkuwOL6i9CT7ncj6z15VDadulvFDPXAc+Z5TCqx2r/8g9jk5CH5lPLoZkRc6SgViFlJKr1rWPft486R5n42V95My/WEP2EekkjfjbofpL3MRjMz20dvPVbWpTMxsSf/aLRvpfFhQO2pb0H0en0eERW38DPKE6Rw==

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants