You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue组件props类型不匹配求助:categoryId期望Number却得到String

问题:Vue组件Props类型不匹配错误

错误信息:

Invalid prop: type check failed for prop "categoryId". Expected Number with value 13, got String with value "13"

将CategoryShow组件的categoryId props类型从String改为Number后出现该错误,此前String类型可正常运行。CategoryHome是CategoryShow的父组件,在CategoryHome中console.log(typeof categoryId)输出为number,但CategoryShow接收的props类型却不匹配,请问代码哪里出错了?

相关代码

CategoryShow.vue

<script setup>
import axios from "axios";
import { ref, watch} from "vue"

import { useRoute, useRouter } from 'vue-router'

const route = useRoute()

const router = useRouter()

const props = defineProps({
  categoryId: {
    //type: String,
     type: Number
  }
})

const categories = ref([])

const singleCategory = ref({})

const recipes = ref([])


const getCategory = () => {
    return axios.get('/api/categories/' + props.categoryId)
}

const getCategories = () => {
    return axios.get('/api/categories')
}

const getRecipes = () => {
    return axios.get('/api/categories/' + props.categoryId + '/recipes/')
}

const getCategoriesAndCategoryAndRecipes = async () => {
    const res1 = await getCategories()
    const res2 = await getCategory()
    const res3 = await getRecipes()
    singleCategory.value = res2.data
    recipes.value = res3.data
    categories.value = res1.data
}

// 组件创建时调用
getCategoriesAndCategoryAndRecipes()

// 监听路由变化
watch(route, () => {
    if (!isNaN(props.categoryId))
    {
        getCategoriesAndCategoryAndRecipes()
    }
})
</script>

<template>
    <div class="left-container">
        <div class="form-box">
            <h4 style="margin-bottom: 20px; margin-top: 10px">RECIPE HOUSE</h4>
            <form method="post" v-on:submit.prevent="addCategory">
                <input type="text" v-model="newCategory">
            </form>
        </div>
        <ul class="category_ul">
            <li v-for="category in categories" :key="category.id">
                <button class="btn btn-danger" v-on:click="deleteCategory(category.id)">Delete</button>
                <router-link :to="{name: 'category.show', params: {categoryId: category.id }}">
                    <span>{{ category.title }}</span>
                </router-link>
            </li>
        </ul>
    </div>

    <div class="right-container">
        <span class="icon">
            <i class="fas fa-utensils fa-lg"></i>
        </span>
        <div>
            <span>{{ singleCategory.title }}</span>
            <form method="post" v-on:submit.prevent="addRecipe">
                <input type="text" v-model="newRecipe">
            </form>
            <ul style="margin-top: 15px;">
                <li v-for="recipe in recipes">
                    <router-link :to="{name: 'recipe.show', params: {recipeId: recipe.id}}">
                        <span>{{ recipe.title }}</span>
                    </router-link>
                </li>
            </ul>
        </div>
    </div>

</template>

CategoryHome.vue

<script setup>
// import axios from "axios"
import { onMounted, ref } from "vue"

import { useRouter } from 'vue-router'

const router = useRouter()

const newCategory = ref('')
let categoryId = ''

async function initial() {
    try {
        const res = await axios.get('/api/max')
        categoryId = res.data.id
        console.log(typeof categoryId) // 输出number
        router.push({name: 'category.show', params: { categoryId: categoryId }})
    } catch(err) {
        console.log('error handling')
    }

}

initial()

</script>

<template>
    <div class="left-container">
        <h4 style="margin-bottom: 20px; margin-top: 10px">RECIPE HOUSE</h4>
        <form method="post" v-on:submit.prevent="addCategory">
            <input type="text" v-model="newCategory">
        </form>
    </div>

</template>

解决方案

问题根源:Vue Router的路由参数默认会被转换为字符串类型,哪怕你传入的是数字,最终通过路由传递到组件的参数都会变成字符串,这就导致CategoryShow组件接收的categoryId是字符串,和你定义的Number类型props不匹配。

解决方法1:在路由定义中自动转换参数类型

找到你的路由配置文件(通常是router/index.js),给category.show路由添加props配置,将参数转为数字:

const routes = [
  // ...其他路由
  {
    name: 'category.show',
    path: '/categories/:categoryId',
    component: () => import('../views/CategoryShow.vue'),
    // 这里将路由参数转为Number类型
    props: route => ({ categoryId: Number(route.params.categoryId) })
  }
]

解决方法2:在组件内部兼容类型并转换

如果不想修改路由配置,可以修改CategoryShow的props定义,允许接收字符串或数字,然后在内部转为数字使用:

const props = defineProps({
  categoryId: {
    type: [Number, String], // 允许两种类型
    required: true
  }
})

// 在使用时转为数字
const numericCategoryId = Number(props.categoryId)

// 修改接口请求的地方,用转换后的数字
const getCategory = () => {
    return axios.get('/api/categories/' + numericCategoryId)
}
const getRecipes = () => {
    return axios.get('/api/categories/' + numericCategoryId + '/recipes/')
}

额外优化:修正watch中的判断逻辑

原代码中!isNaN(props.categoryId)的判断存在问题,因为字符串"13"传入isNaN会被隐式转为数字,返回false,导致判断失效。可以改成:

watch(route, () => {
    const id = Number(props.categoryId)
    if (!isNaN(id)) {
        getCategoriesAndCategoryAndRecipes()
    }
})

内容的提问来源于stack exchange,提问作者sora sakamoto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 18:40:26