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

Vue中如何不使用交集类型从元组数组动态定义ButtonProps类型?

解决方案:不使用交集类型动态定义ButtonProps

问题背景

你原本通过以下TypeScript代码动态定义了Button组件的props类型:

const intents = ["primary", "secondary", "accent", "danger"] as const;
const buttonSizes = ["small", "medium", "big"] as const;
type IntentType = (typeof intents)[number];
type SizeType = (typeof buttonSizes)[number];

type ButtonProps = {
  intent?: IntentType;
  size?: SizeType;
} & {
  [K in IntentType as `${Lowercase<K>}`]?: boolean;
};

但Vue会抛出错误:

Internal server error: [@vue/compiler-sfc] type argument passed to defineProps() must be a literal type, or a reference to an interface or literal type.

静态定义的方式虽可行,但会导致后续遍历intents时出现重复代码,因此需要一种既保留动态生成属性、又不使用交集类型的方案。

可行方案:使用接口扩展替代交集类型

Vue的编译器允许将接口作为defineProps的类型参数,因此可以将动态生成的属性类型与基础props类型通过接口扩展的方式合并,避免直接使用交集类型:

const intents = ["primary", "secondary", "accent", "danger"] as const;
const buttonSizes = ["small", "medium", "big"] as const;
type IntentType = (typeof intents)[number];
type SizeType = (typeof buttonSizes)[number];

// 先定义动态生成的intent标记属性类型
type IntentFlags = {
  [K in IntentType as `${Lowercase<K>}`]?: boolean;
};

// 通过接口扩展合并基础props与动态属性
interface ButtonProps extends IntentFlags {
  intent?: IntentType;
  size?: SizeType;
}

在Vue组件中使用时,直接将ButtonProps传入defineProps即可:

<script setup lang="ts">
// ...上述类型定义
const props = defineProps<ButtonProps>();
</script>

这种方式既保留了动态生成属性的能力(无需重复写primary?/secondary?等属性),又符合Vue编译器对defineProps类型参数的要求,同时后续遍历intents数组时也不会出现重复代码。

内容的提问来源于stack exchange,提问作者Demiro-FE-Architect

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 16:01:02