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

Vue3自定义组件(TS)联合类型Props未触发预期校验问题

Vue3 TypeScript 联合类型Props未触发必填校验问题修复

问题描述

在Vue3+TS自定义组件中定义了联合类型ComponentProps,包含LinkComponentProps(需is='link'和必填url)和BlockComponentProps(需is='section'/'div')。预期传递:is="link"时TS会提示缺少url,但实际未触发错误。

问题根源

Vue的模板类型检查器在处理纯泛型定义的联合类型Props时,不会自动根据判别式字段(这里的is)做类型窄化。即使传入is='link',TS仍将Props视为整个联合类型,认为url可选(因为Block类型不需要),因此不触发报错。

解决方案

通过结合运行时Props验证+TS类型约束的方式,让TS能正确识别判别式对应的必填字段:

修改组件的<script setup lang="ts">部分:

interface BaseComponentProps {
  useHoverEffect?: boolean
}

interface LinkComponentProps extends BaseComponentProps {
  is: 'link'
  url: string
}

interface BlockComponentProps extends BaseComponentProps {
  is: 'section' | 'div'
}

type ComponentProps = LinkComponentProps | BlockComponentProps;

// 改用对象语法定义Props,添加运行时校验规则
const props = defineProps({
  is: {
    type: String as const,
    required: true,
    // 验证is的取值范围
    validator: (value: string): value is ComponentProps['is'] => {
      return ['link', 'section', 'div'].includes(value)
    }
  },
  url: {
    type: String,
    // 仅当is为'link'时要求必填
    required: (props: ComponentProps) => props.is === 'link'
  },
  useHoverEffect: {
    type: Boolean,
    default: false
  }
}) as ComponentProps // 保留联合类型的TS类型提示

const tag = computed(() => {
  return props.is === 'link'
    ? resolveComponent('NuxtLink')
    : props.is
})

const url = computed(() => {
  return props.is === 'link' ? props.url : undefined
})

效果验证

修改后,当使用<Card :useHoverEffect="true" :is="'link'" />时,TypeScript会立即提示缺少必填的url属性,符合预期;而传递is='div'或is='section'时,无需url即可正常使用。

额外说明

  • 确保使用最新版的Volar插件(Vue官方TypeScript支持工具),旧版本对联合类型判别式的支持有限;
  • 运行时的required函数同时兼顾了Vue的运行时校验和TS的类型推导,双重保障组件的Props合法性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 14:19:51