提取 Vue3 组件的 props 类型
项目使用的是 ElementPlus 组件库,在做组件的二次封装时,需要提取 ElTableColumn 组件的属性,网上搜索了一下,可以这样得到属性的类型:
import { ElTableColumn } from 'element-plus'
type TElTableProps = InstanceType<typeof ElTableColumn>['$props'];
类型错误
使用的时候发现 el-table-column 组件提示类型错误,如下使用:
<template>
<el-table>
<el-table-column v-bind="item" />
</el-table>
</template>
<script setup lang="ts">
import { ElTableColumn } from 'element-plus'
type TElTableProps = InstanceType<typeof ElTableColumn>['$props'];
const item: TElTableProps = { prop: 'name' }
</script>
错误信息如下:
Type '{ type?: string | undefined; width?: string | number | undefined; minWidth?: string | number | undefined; sortOrders?: ("ascending" | "descending" | null)[] | undefined; sortable?: string | boolean | undefined; ... 35 more ...; style?: unknown; }' is not assignable to type 'IntrinsicAttributes & Partial<{ type: string; width: string | number; minWidth: string | number; sortOrders: ("ascending" | "descending" | null)[]; sortable: string | boolean; ... 4 more ...; filterMultiple: boolean; }> & Omit<...>'.
Type '{ type?: string | undefined; width?: string | number | undefined; minWidth?: string | number | undefined; sortOrders?: ("ascending" | "descending" | null)[] | undefined; sortable?: string | boolean | undefined; ... 35 more ...; style?: unknown; }' is not assignable to type 'IntrinsicAttributes'.ts(2322)
查看了一下 TElTableProps
的类型发现,这个类型里面大概有两种类型组合:
DefineComponent
中的 props (如: ref, key 等属性)ElTableColumn
中的 props
所以只需要将 ElTableColumn
中的 DefineComponent
的属性移除应该就可以了。
剔除不需要的属性
通过 InstanceType<typeof FooComponent>['$props']
可以获取到组件上所有的属性,通过 keyof
可以得到所有的 key
,最后通过 Omit
剔除包含在 DefineComponent 中的属性:
import type { DefineComponent } from 'vue'
type BaseProps = InstanceType<DefineComponent>['$props']
type TGetComponentPropType<T extends TInstance, O = InstanceType<T>['$props']> = Omit<O, keyof BaseProps>
指定某些属性为必填项
通过上面得到的类型都是可选项,但我需要 prop
属性为必填项,所以还需要做点修改,下面我使用了 type-fest 库:
import type { SetRequired } from 'type-fest'
import type { DefineComponent } from 'vue'
import { ElTableColumn } from 'element-plus'
type BaseProps = InstanceType<DefineComponent>['$props']
type TGetComponentPropType<T extends TInstance, K extends string = '', R = Omit<InstanceType<T>['$props'], keyof BaseProps>> = SetRequired<R, K>
type MyType = TGetComponentPropType<typeof ElTableColumn, 'prop'>
上面 MyType
为所需的类型,但 SetRequired<R, K>
中的 K
ts 会提示错误:
Type 'K' does not satisfy the constraint 'keyof R'.
Type 'string' is not assignable to type 'keyof R'.ts(2344)
大概意思是 K
可能不是 R
的属性,解决方法是通过 Extract
方法取 K
与 keyof R
的交集,最终的代码如下:
import type { SetRequired } from 'type-fest'
import type { DefineComponent } from 'vue'
import { ElTableColumn } from 'element-plus'
type BaseProps = InstanceType<DefineComponent>['$props']
type TGetComponentPropType<T extends TInstance, K extends string = '', R = Omit<InstanceType<T>['$props'], keyof BaseProps>> = SetRequired<R, Extract<keyof R, K>>
type MyType = TGetComponentPropType<typeof ElTableColumn, 'prop'>