Support for using discriminated union props with `defineComponent` and runtime props
Vue version
3.3.4
Link to minimal reproduction
https://github.com/justin-schroeder/vue-3.3-prop-unions
Steps to reproduce
Clone the repository and install:
git clone git@github.com:justin-schroeder/vue-3.3-prop-unions.git
cd vue-3.3-prop-unions.git
pnpm install
pnpm build
What is expected?
There are 2 ideas to highlight here:
TypeScript
The example defines a component using the new function syntax for defineComponent
with a discriminated union as the prop type. Each union type has 1 prop the other type does not have (bar
vs foo
). The runtime props include both bar
and foo
to ensure they are both accepted at runtime.
import { defineComponent, h } from "vue"
import type { RenderFunction } from "vue"
type Pizza = { type: "pizza"; toppings: "pepperoni" | "pineapple"; bar: string }
type Pie = { type: "pie"; toppings: "apple" | "cherry"; foo: string }
type PropUnion = Pizza | Pie
export default defineComponent(
function setup<P extends PropUnion>(props: P): RenderFunction {
return () => h("div", `${props.type} with ${props.toppings}`)
},
{
props: ["type", "toppings", "foo", "bar"],
}
)
I would expect this to work properly since the runtime props are inclusive of all unions, there is no overload that allows for the runtime props to differ from the union props even if the runtime props are only defining additional props. Volar is actually ok with this typing, but Vue itself does not have a matching component overload. For example:
Adding an additional overload for defineComponent
seems like it may sufficiently address this.
Runtime prop proposal
Alternatively, it would be ideal to allow for runtime props to be determined at runtime. This seems like it would be primary beneficial to library authors, so perhaps no SFC compatibility is necessary. One option:
// Signature:
DefineComponent<P, E...>(setup<P>(props: P, context: SetupContext<E, S>): RenderFunction, options?: Omit<ComponentOptions, 'props'> & { props: (allAttrs: Record<string, any>): P }): (props: P & EmitsToProps<E>) => any
defineComponent(
function setup<P>(props: P) {
//...
},
{
props (allAttrs: Record<string, any>): P /* <-- actual runtime props */ {
if (allAttrs.type === 'foo') {
return ['a', 'b', 'c']
}
return ['d', 'e', 'f']
}
}
)
What is actually happening?
No overload matches this call
System Info
System:
OS: macOS 13.1
CPU: (10) arm64 Apple M1 Pro
Memory: 84.44 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: 114.1.52.126
Chrome: 114.0.5735.133
Edge: 114.0.1823.51
Firefox: 111.0.1
Safari: 16.2
npmPackages:
vue: ^3.3.4 => 3.3.4
Any additional comments?
No response
duplicate of https://github.com/vuejs/core/issues/9335
Closing this one, because the other one has a PR attached.