vue 3 + typescript 中单文件组件的 props 泛型支持需通过 definecomponent 和 defineprops 显式泛型声明实现,推荐先定义泛型接口再传入 defineprops,配合 withdefaults 保持泛型完整性,并可提取为独立类型文件复用。

Vue 3 + TypeScript 中,单文件组件(SFC)的 Props 泛型支持需要借助 defineComponent 和 defineProps 的显式泛型声明方式实现。直接在 <script setup></script> 中用 defineProps<t>()</t> 是无效的——TypeScript 不允许泛型参数直接用于调用签名,必须通过类型参数推导或 as const + 类型断言等间接方式实现。
使用 defineProps 配合泛型接口(推荐)
最清晰、可维护的方式是先定义一个泛型接口,再将其传给 defineProps:
- 在
<script setup lang="ts"></script>中,声明一个带类型参数的接口,如Props<t></t> - 用
defineProps<props>>()</props>显式指定具体类型 - 这样既保留类型安全,又支持子组件接收不同类型的 props(如
data: T[]、formatter: (v: T) => string)
示例:
interface Props<t> {
items: T[];
keyName?: string;
formatter?: (item: T) => string;
}
const props = defineProps<props>>();
</props></t>
利用 withDefaults 保持泛型完整性
如果泛型 Props 需要默认值,不能直接对泛型调用 withDefaults,而应先构造 props 类型,再包裹:
- 先用
defineProps获取泛型 props 类型(不带默认值) - 再用
withDefaults传入相同泛型接口,并提供默认值对象 - 确保默认值类型与泛型约束一致(例如
T不能是never或未约束的unknown)
示例:
interface ListProps<t> {
data: T[];
emptyText?: string;
}
const props = withDefaults(
defineProps<listprops>>(),
{
emptyText: 'No data'
}
);
</listprops></t>
避免常见错误:不要在 defineProps 调用中直接写泛型函数
以下写法 ❌ 会报错或失去类型推导:
-
defineProps<t>()</t>—— TypeScript 不允许泛型调用签名无上下文 -
defineProps()——T未声明,编译失败 - 试图在 SFC 内部用
type Props<t> = ...</t>然后defineProps<props>>()</props>——T作用域不存在
正确做法是把泛型约束移到接口或类型别名定义处,并在实例化时填入具体类型。
进阶:组合式函数中复用泛型 Props 类型
当多个组件共享同一套泛型逻辑时,可将泛型 Props 提取为独立类型文件:
- 新建
types/list-props.ts,导出export type ListProps<t> = { data: T[]; ... }</t> - 各组件中直接导入并使用
defineProps<listprops>>()</listprops> - 配合
defineEmits()可实现完整泛型事件契约
这样既提升复用性,也便于集中管理类型契约和文档注释。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











