skip to content

In Vue 3, what actually happens when a prop fails its type, required or validator check, and what can a validator see?

level: middleimportance: should knowfreq 42%

answer

  1. console, not exception
  2. development builds only
  3. value still reaches the child
  4. null and undefined skip checks
  5. validator(value, props) since 3.4

basics

~20 s

Vue only logs a console warning, and only in development builds; the value is still passed and the component renders. Production builds skip validation entirely. A validator receives the value and, since 3.4, the resolved props as a second argument.

solid answer

~40 s

Prop validation in Vue 3 is a development aid. When a check fails, Vue logs `Missing required prop`, `Invalid prop: type check failed` or `Invalid prop: custom validator check failed` and carries on: the child still receives the bad value. Production builds skip validation completely. The checks run in order: a missing required prop warns and stops; an optional prop that is `null` or `undefined` skips the type check and the validator; a failed type check warns and skips the validator. A `validator(value, props)` receives the value and, since 3.4, the resolved props; it runs during prop resolution on each update, so it cannot see setup state. Treat it as a contract check for developers, never as a guard for untrusted data.

code

vue · 18 lines
vue
<script setup>
const props = defineProps({
  min: { type: Number, default: 0 },
  max: {
    type: Number,
    required: true,
    validator: (value, props) => value >= props.min
  },
  size: {
    type: String,
    validator: (v) => ['sm', 'md', 'lg'].includes(v)
  }
})
</script>

<template>
  <input type="range" :min="props.min" :max="props.max" :class="props.size" />
</template>

go deeper

for a junior

Know that failed prop checks only log warnings in the console during development.

for a middle

Walk through the check order, the nullish shortcut, [String, null], and the 3.4 props argument to validator.

for a senior

Explain why validation is not a trust boundary and where real input validation belongs instead.

for a principal

Weigh how much contract checking a shared component library should rely on dev warnings versus types and tests.

## Validation is a development-time warning Vue 3 lets a component describe requirements for its props through `type`, `required` and `validator`. These checks exist to help the developer who **uses** the component. When one fails, the runtime calls its dev warning helper and moves on: - **No exception** is thrown, and the render is not interrupted. - The **value is not coerced or dropped**: the child receives exactly what the parent passed. - In **production builds** the whole validation step is compiled out, so there is not even a warning. That last point is the one interviewers look for. A `validator` is not input sanitisation; data from users or APIs must be checked by your own code. ## The order of checks For each declared prop, the runtime validates in this order when the component is created and again when its props update: 1. **Required** — if `required: true` and the parent did not pass the prop, it warns `Missing required prop: "userId"` and stops checking that prop. 2. **Nullish shortcut** — if the value is `null` or `undefined` and the prop is not required, validation ends silently. Neither the type check nor the validator runs. 3. **Type check** — the value must match at least one listed type (`String`, `Number`, a custom class via `instanceof`, and so on). A mismatch warns `Invalid prop: type check failed for prop "userId". Expected Number, got String …` and stops there, so the validator is not run. 4. **Custom validator** — `validator(value, props)` returning a falsy value warns `Invalid prop: custom validator check failed for prop "userId".` | Situation | Warning | Validator runs? | |---|---|---| | Required prop omitted | Missing required prop | no | | Optional prop omitted or `undefined` | none | no | | Optional prop passed `null` | none | no | | Required prop passed `null`, `type: String` | type check failed | no | | Required prop passed `null`, `type: [String, null]` | none | yes | | Wrong type | type check failed | no | | Right type, predicate false | custom validator check failed | yes | The `[String, null]` array syntax is how you declare a **required but nullable** prop. A bare `type: null` (not in an array) disables type checking altogether. ## What a validator can see The signature is `validator(value, props)`: - **`value`** — the resolved value of this prop, after defaults and Boolean casting. - **`props`** — the full resolved props object, added in Vue 3.4, so cross-prop rules like "`max` must be at least `min`" are possible. In development it is passed read-only. A validator runs during prop resolution, outside the component's `setup`. It therefore cannot read refs or functions from `<script setup>`, and in the Options API it has no `this`: props are validated before the instance's data and computed exist. ## Designing useful validators - Keep them **pure and cheap**; they run on every props update in development. - Use them for **enum-like strings** (`['sm', 'md', 'lg'].includes(value)`) and cross-prop invariants. - Remember a validator on an optional prop never sees `undefined` or `null`, so it need not guard against them; a validator on a required nullable prop does. - Do not rely on them in tests of production behaviour: the checks are gone there. ## Why this design Vue treats props as a **contract between components written by developers**, not as a trust boundary. Running full validation in production would cost time on every render for problems that should be caught while developing, so the runtime keeps the check in development builds and strips it from production ones. ## Reading the warning text The type-check message is more precise than people expect. For a `Number` prop that receives the string `"7"`, the development build reports that it expected `Number with value 7` and got `String with value "7"`, which points straight at a missing `:` in the parent's template (`count="7"` instead of `:count="7"`). Multiple accepted types are listed with `|` between them. The warning also carries a component trace, so you can see which parent passed the value. A declaration of `type: []` gets its own warning that the prop type won't match anything, suggesting you meant `Array`: a small typo trap worth knowing when reading a colleague's console output.

  • How do you declare a Vue 3 prop that must be passed but may be null?
    Use the array syntax with `null`: `{ type: [String, null], required: true }`. Omitting the prop warns as missing, while an explicit `null` passes the type check. A plain `type: String` with `required: true` would warn on `null`, and a bare `type: null` disables type checking altogether.
  • Why is a failing Vue 3 prop validator not a safe place to reject bad user input?
    Because it does nothing at runtime beyond a warning, and only in development builds. The value still reaches the component, and production builds skip validation entirely. Untrusted data must be validated and handled in your own code or form logic, with a visible error path.

saying these in an interview costs you the question

  • Thinks a failed prop check throws and stops the render
  • Believes prop validation also runs in production builds
  • Expects Vue to coerce a mismatched value to the declared type
  • Believes a validator on an optional prop runs when the prop is omitted
  • Tries to read script setup refs inside a validator