@vue/compiler-sfc cannot build <script setup> components that use generic discriminated union props
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>
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_
should be
// props.ts
type Text = { text: string }
type Number = { number: number }
sorry, I misread.
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.
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
?
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>
@justin-schroeder Can you try this plz