The Problem
Vue prop validation warns when a parent passes a value of the wrong type. The most common mismatch is passing a string (e.g., from HTML attributes or API data) where a number is expected.
Symptoms
- Console warning: "Invalid prop: type check failed for prop X. Expected Number, got String"
- Mathematical operations return NaN or concatenated strings
- Comparisons fail (e.g.,
5 === '5'is false) - Component behavior is incorrect but no crash
Real Error Message
[Vue warn]: Invalid prop: type check failed for prop "count".
Expected Number with value 5, got String with value "5".
at <Counter count="5" >Common Causes
Cause 1: HTML Attributes Are Always Strings
```vue <!-- WRONG: This passes the STRING "5", not the number 5 --> <Counter count="5" />
<!-- CORRECT: Use v-bind for numbers --> <Counter :count="5" /> ```
Cause 2: API Data Returns String Numbers
```javascript // API returns: { id: "42", quantity: "10" } const data = await fetch('/api/products').then(r => r.json());
// WRONG: Passing string numbers to number props <ProductCard :price="data.price" :quantity="data.quantity" /> ```
Cause 3: Route Params Are Strings
```javascript // URL: /products/42 // route.params.id is the STRING "42"
// WRONG <ProductDetail :productId="$route.params.id" /> ```
How to Fix It
Fix 1: Use v-bind for Literal Numbers
<Counter :count="5" />
<Grid :columns="3" :gap="16" />
<Timer :duration="30" />Fix 2: Type Coerce in the Child Component
```vue <script setup> const props = defineProps({ count: { type: [Number, String], required: true, validator: (value) => !isNaN(Number(value)) } });
// Coerce to number internally const numericCount = computed(() => Number(props.count)); </script> ```
Fix 3: Coerce at the Call Site
<ProductDetail :productId="Number($route.params.id)" />
<ProductCard :price="Number(data.price)" :quantity="Number(data.quantity)" />Fix 4: Use a Composable for API Data Transformation
function useTypedProducts(apiData) {
return computed(() => apiData.map(p => ({
...p,
id: Number(p.id),
price: Number(p.price),
quantity: Number(p.quantity)
})));
}Strict Prop Validation
defineProps({
count: {
type: Number,
required: true,
validator: (value) => Number.isInteger(value) && value > 0
}
});