发布于 6 个月前 ,更新于 6 个月前 vue,typescript

提取 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 方法取 Kkeyof 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'>
© 2016 - 2022 BY 禾惠 粤ICP备20027042号