New Aug 18, 2025

Pass props with conditional typings in VueJS and TypeScript

Libraries, Frameworks, etc. All from Newest questions tagged vue.js - Stack Overflow View Pass props with conditional typings in VueJS and TypeScript on stackoverflow.com

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?

Scroll to top