Vue3数据表格组件中,如何基于Format组件的Data Prop类型为IColumn的value函数指定对应返回类型
Vue3数据表格组件中,如何基于Format组件的Data Prop类型为IColumn的value函数指定对应返回类型
我完全懂你的痛点——现在用unknown确实太模糊了,没法享受到TypeScript的类型检查优势。其实只要用TypeScript的条件类型+类型推断,就能让value函数的返回类型和对应format组件的data prop类型严格绑定起来,我来一步步给你拆解怎么做:
第一步:定义提取组件Data Prop的工具类型
首先我们需要一个工具类型,能从任意Vue组件中提取出它的data prop的类型。Vue官方提供了ComponentProps类型,可以帮我们获取组件的props定义,再结合infer关键字就能推断出data的类型:
import type { Component, ComponentProps } from 'vue'; // 从组件中提取data prop的类型,没有则返回unknown type ExtractDataPropType<C> = C extends Component ? ComponentProps<C> extends { data: infer D } ? D : unknown : unknown;
第二步:改造IColumn接口
接下来把IColumn改成泛型接口,让它关联行数据类型T和格式组件类型C,这样value函数的返回类型就能自动匹配format组件的data类型:
export interface IColumn<T = any, C = Component | undefined> { id: number; label?: string; // 补上你示例里用到的label字段 /** Vue组件,必须包含data prop */ format?: C; /** 返回值严格对应format组件的data prop类型 */ value?: (row: T) => ExtractDataPropType<C>; }
第三步:改造DataTable组件的Props
如果你的Vue版本是3.3+,可以直接在<script setup>里使用泛型组件,让整个表格组件关联行数据类型T,这样类型检查会更彻底:
<script setup lang="ts" generic="T"> import type { Component, ComponentProps } from 'vue'; // 工具类型 type ExtractDataPropType<C> = C extends Component ? ComponentProps<C> extends { data: infer D } ? D : unknown : unknown; // 泛型IColumn接口 export interface IColumn<C = Component | undefined> { id: number; label?: string; format?: C; value?: (row: T) => ExtractDataPropType<C>; } // 定义组件props,rows类型和泛型T绑定 defineProps<{ cols: IColumn[]; rows: T[]; }>(); </script> <template> <table> <tbody> <tr v-for="row in rows" :key="row.id"> <td v-for="col in cols" :key="col.id"> <component v-if="col.format" :is="col.format" :data="col.value?.(row)" /> <span v-else>{{ col.value?.(row) }}</span> </td> </tr> </tbody> </table> </template>
第四步:使用时的类型检查
现在当你定义列配置的时候,TypeScript会自动检查value函数的返回值是否和format组件的data类型匹配:
<script setup lang="ts"> import DataTable from './DataTable.vue'; import FNumber from './FNumber.vue'; import FString from './FString.vue'; import FDateRange from './FDateRange.vue'; interface User { id: number; name: string; created_at: string; expire_at: string; } const rows: User[] = [ { id: 1, name: 'John', created_at: '2022-10-10', expire_at: '2022-10-11' }, { id: 2, name: 'Jane', created_at: '2022-07-10', expire_at: '2022-11-11' }, { id: 3, name: 'Anna', created_at: '2022-10-07', expire_at: '2023-11-10' }, ]; // 这里TypeScript会自动检查每个列的value返回值是否匹配format的data类型 const cols: IColumn<User>[] = [ { id: 1, label: 'ID', format: FNumber, // 假设FNumber的data prop是number类型 value: (user) => user.id, // ✅ number类型,匹配 }, { id: 2, label: 'Name', format: FString, // 假设FString的data prop是string类型 value: (user) => user.name, // ✅ string类型,匹配 }, { id: 3, label: 'Activity', format: FDateRange, // FDateRange的data prop是{ dateFrom: Date; dateTo: Date; } value: (user) => ({ dateFrom: new Date(user.created_at), // ✅ 转成Date类型,匹配 dateTo: new Date(user.expire_at), }), }, ]; </script> <template> <!-- 指定泛型类型User,让表格组件知道行数据的类型 --> <DataTable<User> :cols="cols" :rows="rows" /> </template>
注意事项
- 确保你的Vue版本是3.3及以上,这样才能支持
<script setup>的泛型语法,以及更准确的类型推断。 - 如果某个列不需要
format组件,value函数的返回类型会是unknown,你可以直接在模板里渲染,或者调整工具类型让它返回any(不过尽量保持类型安全,不推荐)。 - 自定义组件的
defineProps一定要写对类型,这样ComponentProps才能正确提取data的类型。
内容来源于stack exchange
相关产品推荐
相关产品推荐

