I have 2 props: modelValue and range. The type of modelValue is conditional on the value of range. If true, I want modelValue to be of the type [number, number]; if false, I want modelValue to have the type number.
interface SharedProps {
...rest of props
}
type Props = SharedProps &
(
| { range: true; modelValue: [number, number] }
| { range?: false; modelValue: number }
)
const props = defineProps<Props>()
const emit = defineEmits<{
(e: 'update:modelValue', value: typeof props.modelValue): void
}>()
// Destructure with defaults
const {
modelValue,
range,
...rest of props
} = props
Now in my component this works:
const tempValue = ref<number>(10)
<VelSliderInput
v-model="tempValue"
:max="10"
:min="0"
/>
and when I add range as a prop:
<VelSliderInput
v-model="tempValue"
:max="10"
range
:min="0"
/>
I get the error as expected:
Argument of type '{ modelValue: number; max: number; range: true; min: number; }' is not assignable to parameter of type ...
Types of property 'modelValue' are incompatible.
Type 'number' is not assignable to type '[number, number]'.
Now when I use :model-value and @update:model-value:
<VelSliderInput
:model-value="tempValue"
:max="10"
:min="0"
@update:model-value="tempValue = $event"
/>
I get the error:
Type 'number | [number, number]' is not assignable to type 'number'.
Type '[number, number]' is not assignable to type 'number'.
Probably because in my emit I'm using a union type and not a discriminated union / conditional type.
Question: how can I emit a discriminated union / conditional type, so that I don't need to type cast in my component?