透传时的类型声明
完整导入一个组件的所有属性可借由透传实现
也可以控制非props属性不透传
对于一个完善的组件(比如element-plus、prime-vue)往往具有完备的类型声明,在透传时同样希望完整映射原组件的类型
在vue.js中,defineProps不支持复杂类型(比如动态类型推导Record、[K in keyof T]),如下:
// popover-items.ts
import type { ElPopover } from 'element-plus'
import type { RawProps } from './popover-items-type'
export const popoverItemsProps = {
// 新增 props
// foo: {
// type: String,
// default: 'foo',
// },
} as const
// 自动继承 ElPopover 所有 props + 合并新增 props
export type PopoverItemsProps = RawProps
// 自动继承 ElPopover emits + 合并新增 emits
export type PopoverItemsEmits
= InstanceType<typeof ElPopover>['$emit']
& ((event: 'select', idx: number, vnode: any) => void)
export const popoverItemsEmits = {
select: (idx: number, _vNode: any) => !Number.isNaN(idx),
} as const
// popover-items.vue
const props = defineProps<Partial<PopoverItemsProps>>()
// popover-items-type.d.ts
import type { PopoverProps } from 'element-plus'
import type { ExtractPropTypes } from 'vue'
import type { popoverItemsProps } from './popover-items'
export type RawProps
= PopoverProps
& ExtractPropTypes<typeof popoverItemsProps>
打包时将会提示[vite:vue] [@vue/compiler-sfc] Unresolvable type: TSTypeQuery
尽管此时类型已经完全交由ts生成
解决方式
- 显示定义: 对于一个属性较少、类型较简单的组件完全足够
- 完整映射:
使用element-plus定义的元组,进行组合
import type { PopoverEmits, PopoverProps } from 'element-plus'
// import type { PropType } from 'vue'
import { popoverEmits, popoverProps } from 'element-plus'
// 直接继承 Element Plus 的运行时 props 定义
export const popoverItemsProps = {
...popoverProps,
// 新增 props
// items: {
// type: Array as PropType<Array<{ label: string, value: any }>>,
// default: () => [],
// },
} as const
// 直接继承 Element Plus 的运行时 emits 定义
export const popoverItemsEmits = {
...popoverEmits,
// 新增 emits
select: (idx: number, _vNode: any) => !Number.isNaN(idx),
} as const
// 类型定义
export type PopoverItemsProps = PopoverProps & {
items?: Array<{ label: string, value: any }>
}
export type PopoverItemsEmits = PopoverEmits & {
select: [idx: number, vnode: any]
}
对于不存在的属性元组,可以尝试访问实例的属性
import type { PopoverProps } from 'element-plus'
import type { PropType } from 'vue'
// popover-items.ts
import { ElPopover } from 'element-plus'
// 从组件实例获取 props 定义
const elPopoverProps = (ElPopover as any).props ?? {}
const elPopoverEmits = (ElPopover as any).emits ?? {}
export const popoverItemsProps = {
...elPopoverProps,
// 新增 props
items: {
type: Array as PropType<Array<{ label: string, value: any }>>,
default: () => [],
},
} as const
export const popoverItemsEmits = {
...elPopoverEmits,
select: (idx: number, _vNode: any) => !Number.isNaN(idx),
} as const
export type PopoverItemsProps = PopoverProps & {
items?: Array<{ label: string, value: any }>
}