Vue 3组合式API中泛型通用组件需贯穿props定义、逻辑封装、模板约束和组合函数设计四环节:props须显式声明泛型并避免直接解构,组合函数需泛化参数与返回值类型,模板依赖编译器自动推导类型,调用时优先自动推导,必要时显式指定。
在 Vue 3 组合式 API 中结合 TypeScript 使用泛型编写通用组件,核心是让组件能接收类型参数,从而保证 props、事件、内部状态和返回值的类型安全。这不是“加个 <T> 就完事”,而是要贯穿 props 定义、逻辑封装、模板约束和组合函数设计四个关键环节。
Vue 3 的 defineProps 支持泛型推导,必须用类型参数显式声明,不能靠类型断言或 any。
defineProps<T>() 或更推荐的 defineProps<{ list: T[]; onItemClick: (item: T) => void }>() 显式约束结构const { list } = props),否则会丢失响应性和类型关联;需用 toRefs 或保持原对象访问type ItemType = typeof props.list extends Array<infer U> ? U : never
把可复用逻辑抽成带泛型的函数,是实现类型安全复用的关键。例如分页逻辑、搜索过滤、表单校验等。
function useListFilter<T>(list: Ref<T[]>, filterFn: (item: T, keyword: string) => boolean)
Ref<T[]>、ComputedRef<T[]>,而非硬编码 Ref<User[]>
ref 和 computed 时,泛型需传递到底层响应式对象,例如 const filtered = computed<T[]>(() => ...)
Vue 模板本身不写类型,但编译器会根据 defineProps 和 defineEmits 的泛型定义自动推导插槽作用域、事件参数和 v-model 绑定类型。
v-model 在泛型组件中仍保持类型联动:若 modelValue 是 T,则绑定变量也必须是 T 类型<template #item="{ item }">)中 item 的类型由 props 泛型决定,IDE 能准确提示属性item as User),应靠 props 定义源头保障父组件使用时,TypeScript 通常能自动推导泛型,但复杂场景需显式传入。
<List :list="users" @item-click="handleUser" />)中,users: User[] 会让组件自动推导 T = User
<List<Product> :list="products" /> 显式指定defineComponent 或 defineAsyncComponent 时,泛型需写在组件工厂函数上,而非模板标签中