Vue+TypeScript中defineProps用never类型触发Vite报错求助
解决方案
问题根源
Vue单文件组件的编译器不支持将联合类型作为defineProps的泛型参数,这就是你看到报错的原因。React允许联合类型直接用于props,但Vue的SFC编译逻辑要求泛型参数必须是单一接口或字面量类型。
修复后的代码
<template> <component :is="component" :to="to" :href="href" @click="$emit('click')"> <slot /> </component> </template> <script setup lang="ts"> import { computed } from 'vue' // 定义包含所有基础属性的接口(含可选的to/href) interface ButtonBaseProps { type?: string size?: "sm" | "md" | "lg" disabled?: boolean loading?: boolean to?: string href?: string } // 定义互斥类型:确保to/href不同时存在,或都不存在 type ButtonProps = | (ButtonBaseProps & { to: string; href?: never }) | (ButtonBaseProps & { href: string; to?: never }) | (ButtonBaseProps & { to?: never; href?: never }) // 用对象式defineProps定义属性,添加运行时校验确保互斥,同时设置默认值 const props = withDefaults(defineProps<ButtonBaseProps>({ to: { type: String, default: undefined, validator: (val?: string) => val === undefined || props.href === undefined }, href: { type: String, default: undefined, validator: (val?: string) => val === undefined || props.to === undefined } }), { type: "button", size: "md", disabled: false, loading: false }) as ButtonProps // 合并原computed逻辑到script setup const component = computed(() => { if (props.to || props.href) return resolveComponent("NuxtLink") return "button" }) // 定义emit类型 defineEmits<{ click: [] }>() // 定义组件名,替代原额外的script标签 defineOptions({ name: "CButton" }) </script>
关键说明
类型层面的互斥约束:
先定义包含所有可选属性的ButtonBaseProps作为defineProps的泛型参数(满足Vue编译器要求),再通过类型断言将props转为ButtonProps联合类型,让TypeScript在编译时校验to和href的互斥性。运行时校验:
在to和href的validator函数中确保两者不同时存在,避免编译后用户传入非法值。代码精简与Vetur支持:
- 用
defineOptions定义组件名,去掉冗余的第二个script标签; - 对象式
defineProps能被Vetur正确识别,无需额外配置即可获得props提示。
- 用
兼容性:
该方案适配Vue 3 + Nuxt 3 + TypeScript,符合script setup的最新规范,同时保留了你的核心需求:to和href二选一或都不传。
内容的提问来源于stack exchange,提问作者indiehjaerta
相关产品推荐
相关产品推荐

