Skip to content

@vue/compiler-sfc cannot build <script setup> components that use generic discriminated union props #8468

@justin-schroeder

Description

@justin-schroeder

Vue version

3.3.4

Link to minimal reproduction

https://github.com/justin-schroeder/generics-discriminated-union-reproduction

Steps to reproduce

Any component with generics, where the generics extend a discriminated union cannot be compiled by @vue/compiler-sfc — however, they work just fine with Volar.

// Input.vue
<script setup lang="ts" generic="P extends Inputs">
import type { Inputs } from '../props.ts'

defineProps<P>()
</script>
// props.ts
type Text = { type: 'text', value: string }
type Number = { type: 'number', value: number }

export type Inputs = Text | Number

What is expected?

Typed prop unions work both in both Volar and build time.

What is actually happening?

The following error is thrown:

[vite] Internal server error: [@vue/compiler-sfc] Unresolvable type reference or unsupported built-in utility type

/src/components/Input.vue
2  |  import type { Inputs } from '../props.ts'
3  |  
4  |  const props = defineProps<P>()
   |                            ^
5  |  </script>

Screenshot 2023-05-31 at 1 46 37 PM

Full reproduction repository here: https://github.com/justin-schroeder/generics-discriminated-union-reproduction

System Info

System:
    OS: macOS 13.1
    CPU: (10) arm64 Apple M1 Pro
    Memory: 63.72 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 18.14.2 - /usr/local/bin/node
    Yarn: 1.22.18 - ~/.yarn/bin/yarn
    npm: 9.5.0 - /usr/local/bin/npm
  Browsers:
    Brave Browser: 113.1.51.118
    Chrome: 113.0.5672.126
    Edge: 113.0.1774.57
    Firefox: 111.0.1
    Safari: 16.2
  npmPackages:
    vue: 3.3.4 => 3.3.4


### Any additional comments?

_No response_

Activity

edison1105

edison1105 commented on Jun 1, 2023

@edison1105
Member

should be

// props.ts
type Text = { text: string }
type Number = { number: number }

sorry, I misread.

justin-schroeder

justin-schroeder commented on Jun 1, 2023

@justin-schroeder
Author

🤔 no, that's not the intended props. I did in fact mean the discriminated union that was provided.

sxzz

sxzz commented on Jun 11, 2023

@sxzz
Member

Currently, Vue disallows dynamic props keys that from TS types. Because Vue's compiler needs to analyze TS types and transform them into the runtime definition of a specific prop, and it cannot be analyzed statically in build time.

justin-schroeder

justin-schroeder commented on Jun 12, 2023

@justin-schroeder
Author

Ok, that actually makes a lot of sense @sxzz.

Related: Has any consideration been giving to providing a mechanism to remove the distinction of props/attrs and treating all of them the same (as props)? This would be useful for library authors who would like to create dynamic prop APIs. To prevent breaking changes this could be an opt-in option on a per-component basis, similar to inheritAttrs?

unrevised6419

unrevised6419 commented on Oct 30, 2023

@unrevised6419

Hey there! Another use case.
My example is different, but the error message seems the same (not related to discriminated unions).

There are compiler errors, but Volar seems to work fine.

Error: [@vue/compiler-sfc] Unresolvable type reference or unsupported built-in utility type

src/LocalScope.vue
4  |  
5  |  <script setup lang="ts" generic="TProps extends Record<string, unknown>">
6  |  const props = defineProps<TProps>()
   |                            ^^^^^^

Code

<template>
  <slot v-bind="props" />
</template>

<script setup lang="ts" generic="TProps extends Record<string, unknown>">
const props = defineProps<TProps>()

defineSlots<{
  default(props: TProps): JSX.Element
}>()
</script>

Usage

<script setup>
import LocalScope from './LocalScope.vue'
</script>

<template>
  <LocalScope v-slot="{ test, lorem, ipsum }" :lorem="42" ipsum="dolor">
                     // ^ expected TS error
    <span>{{ test }}</span>
    <span>{{ lorem }}</span>
    <span>{{ ipsum }}</span>
  </LocalScope>
</template>

https://play.vuejs.org/#eNp9U01v2zAM/SuELm0BzwHWnQw3wDbksGLYiqaHHXTxZMZTK0uCRKUBAv/3UfKaOsPWm/keHz/E56P46H29Tyga0UYVtCeISMmvpdWjd4Hgq1Od2SrnEXbBjXBRr16hLL2Qtl3NWlZxQDh60xFyBNAu9Pt30Ti6keIIhJEqMC7gWIH2MY0wSQFNQTjjw3uOCs5B7xiWotTjitF3dn2ca8A0cfMM/EWWQv9l/3Rcsu1iLQba1WkNUQmKytmdHurH6Cy/1TErpFBu9Npg+O5JOxulaKAwmeuMcc+3BaOQsHrB1S9UT//AH+MhY1LcBYwY9ijFiaMuDEgzvdl+wwN/n8jR9clw9hvkPUZnUp5xTvuUbM9jL/LKtF/KxbUdHuLmQGjjy1J50Jw5lXwp+Oqf31j9ddzr+rropJ34Fc99ky13bpXsDjbJT217vroPznNdWJ1fo1hsaVUwnR04n3LygBaDVhw+3GU98HOg7SPco3KhbyMF3q+CZJ+se+bLZ1fxbdlJpR/cQI87bbGo27nI+vIqd52JLQ8Z27IrA10ydFmUDczJVw3cbn/UG4MjWuLFi/r0h4jpN/g9LEw=

so1ve

so1ve commented on Nov 4, 2023

@so1ve
Member
added a commit that references this issue on Nov 4, 2023
unrevised6419

unrevised6419 commented on Oct 23, 2024

@unrevised6419

I was able to achieve my case using this implementation.

LocalScope.vue

<script setup lang="ts" generic="T">
defineOptions({ inheritAttrs: false })
defineProps</* @vue-ignore */ T>()
</script>

<template>
  <slot v-bind="$attrs as T" />
</template>

App.vue

<script setup>
import LocalScope from './LocalScope.vue'
</script>

<template>
  <LocalScope item-classes="rounded p-3 bg-blue-500" #default="{ itemClasses }">
    <div :class="itemClasses">
      No Data
    </div>

    <div :class="itemClasses">
      Loading
    </div>

    <div :class="itemClasses">
      Error
    </div>

    <div :class="itemClasses">
      Data
    </div>
  </LocalScope>
</template>
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

      Development

      No branches or pull requests

        Participants

        @unrevised6419@justin-schroeder@edison1105@sxzz@so1ve

        Issue actions

          @vue/compiler-sfc cannot build <script setup> components that use generic discriminated union props · Issue #8468 · vuejs/core