如何判断emit是否已定义?Vue自定义事件类型校验报错解决
解决Vue 3 emit类型校验失败问题:判断事件是否已定义
问题原因
你定义的UsePressableEmits是联合类型,表示emit要么同时支持press和longPress,要么仅支持press。当你把defineEmits创建的函数赋值给这个类型时,TypeScript会默认取联合类型的交集逻辑——仅确保press事件一定存在,因此调用emit("longPress")时会触发类型校验错误。
解决方案
1. 调整Emits类型定义(推荐)
改用Vue 3官方推荐的对象形式事件类型,通过?标记可选事件,避免联合类型带来的歧义:
// 定义事件映射:键为事件名,值为参数数组(可选事件用?标记) type PressableEventMap = { press: [event: Event]; longPress?: [event: Event]; }; // 创建emit时直接使用该类型 const emit = defineEmits<PressableEventMap>();
2. 用类型守卫判断事件是否支持
如果需要保留原联合类型定义,可以通过类型守卫在类型层面判断emit是否支持longPress:
// 类型守卫函数:筛选出支持longPress的emit类型分支 function supportsLongPress( emit: UsePressableEmits ): emit is Extract<UsePressableEmits, { (e: "longPress", event: Event): void }> { // 运行时无法直接检测函数调用签名,可根据业务逻辑调整判断条件 // 例如:若组件接收了onLongPress props则返回true return true; } // 使用示例 function fireLongPress(event: Event) { firing.value = true; if (supportsLongPress(emit)) { emit("longPress", event); // 此时类型校验通过 } firing.value = false; }
3. 简化类型定义(无需严格区分可选事件)
如果你的场景中longPress是可选但允许任意调用(即使无监听),可以直接简化类型为包含所有事件的函数类型:
export type UsePressableEmits = { (e: "press", event: Event): void; (e: "longPress", event: Event): void; }; // 创建emit时直接使用该类型 const emit = defineEmits<UsePressableEmits>();
这种情况下调用emit("longPress")不会触发类型错误,即使组件未监听该事件,Vue也会静默处理。
内容的提问来源于stack exchange,提问作者Archimedes Trajano
相关产品推荐
相关产品推荐

