Vue 3 中用 TypeScript 接口约束 Props 需结合 defineProps 泛型,支持类型检查、IDE 提示和默认值(withDefaults),泛型组件可复用,模板中自动获得类型提示。

在 Vue 3 单文件组件中,用 TypeScript 接口(interface)约束 Props,核心是结合 defineProps 宏与泛型声明,让类型检查在编译期生效,而不是依赖运行时校验。这种方式能提供精准的 IDE 提示、防止传错字段、避免 any 泛滥,也便于团队协作和后期维护。
定义接口并用于 defineProps
直接用 interface 描述 Props 结构,再作为泛型传给 defineProps:
- 接口名建议 PascalCase(如
UserCardProps),字段语义清晰、可读性强 - 必填字段不加
?,可选字段显式标注(如avatar?: string) - 联合类型、函数、对象、数组都需明确写出,不依赖类型推导
示例:
<script setup lang="ts">
interface ButtonProps {
label: string
size?: 'small' | 'medium' | 'large'
onClick?: (e: MouseEvent) => void
styleConfig?: { color: string; padding: string }
tags?: string[]
}
const props = defineProps<ButtonProps>()
</script>
为可选字段设置默认值(Vue 3.4+)
纯 defineProps<T>() 不支持默认值,必须搭配 withDefaults:
立即学习“前端免费学习笔记(深入)”;
- 第二个参数是默认值对象,键名必须与接口字段完全一致
- 基础类型(string/number/boolean)直接写值;引用类型(Array/Object)必须用函数返回,避免共享引用
- 设置后,该字段在类型上自动变为“必填”,但实际仍可不传(由默认值兜底)
示例:
<script setup lang="ts">
interface ListProps {
items: string[]
emptyText?: string
keyField?: string
}
const props = withDefaults(
defineProps<ListProps>(),
{
emptyText: '暂无数据',
keyField: 'id',
items: () => [] // ⚠️ 注意:数组必须用函数
}
)
</script>
处理泛型组件中的 Props(如列表类组件)
当组件需要适配不同数据结构(比如用户列表、订单列表),可用泛型接口提升复用性:
- 接口本身带泛型参数(如
ListProps<T>),描述通用结构 - 默认值中涉及泛型字段时,类型要对齐(如
keyField: 'id' as keyof T) - 避免把默认值逻辑写死在
withDefaults里,更稳妥的是下沉到接口定义或组件内部逻辑
示例:
<script setup lang="ts">
interface ListProps<T> {
dataSource: T[]
keyField: keyof T | ((item: T) => string | number)
renderItem?: (item: T) => string
}
const props = withDefaults(
defineProps<ListProps<{ id: number; name: string }>>(),
{
keyField: 'id' as const
}
)
</script>
模板中也能享受类型提示
只要 <script setup lang="ts"> 存在,SFC 的 <template> 区域内所有表达式都会启用 TS 类型检查:
-
{{ props.label }}会校验label是否存在、是否为 string -
@click="props.onClick"能识别函数签名,点击事件参数自动补全 - 若传入不符合接口的 prop(如漏掉必填项),VS Code 和构建工具(Vite/Vue CLI)都会实时报错
不需要额外配置,开箱即用。


















