Composition API中如何在Composable里正确类型化defineEmit
解决Vue3 TypeScript中Composable接收emit的类型报错问题
问题根源
EmitType只是你定义的事件类型约束,而defineEmits<EmitType>返回的是带调用签名的函数实例。直接把EmitType作为Composable的参数类型,TypeScript会判定它不是可调用函数,因此抛出报错。
可行解决方案
方案1:用typeof emit自动推导类型(最省心)
在组件里直接通过typeof emit拿到正确的函数类型,传给Composable时用这个类型约束参数:
<!-- 组件代码 --> <script setup lang="ts"> type EmitType = { (e: 'update:modelValue', value: string): void (e: 'submit'): void } const emit = defineEmits<EmitType>() import useMyComposable from './useMyComposable' useMyComposable(emit) </script>
// useMyComposable.ts // 直接用ReturnType获取defineEmits的返回类型 export default function useMyComposable(emit: ReturnType<typeof defineEmits<EmitType>>) { // 这里会自动提示事件名和参数类型 emit('update:modelValue', 'test content') emit('submit') }
方案2:用Vue内置的DefineEmits类型
从vue导入DefineEmits类型,直接定义Composable的参数为DefineEmits<EmitType>:
// useMyComposable.ts import type { DefineEmits } from 'vue' type EmitType = { (e: 'update:modelValue', value: string): void (e: 'submit'): void } export default function useMyComposable(emit: DefineEmits<EmitType>) { emit('update:modelValue', 'new value') emit('submit') }
方案3:抽离共享事件类型(多组件复用场景)
如果多个组件和Composable都要用同一份事件类型,把EmitType单独放到类型文件里,再导入使用:
// types/emits.ts export type FormEmitType = { (e: 'update:modelValue', value: string): void (e: 'submit'): void }
<!-- 组件代码 --> <script setup lang="ts"> import type { FormEmitType } from './types/emits' import useFormComposable from './useFormComposable' const emit = defineEmits<FormEmitType>() useFormComposable(emit) </script>
// useFormComposable.ts import type { DefineEmits } from 'vue' import type { FormEmitType } from './types/emits' export default function useFormComposable(emit: DefineEmits<FormEmitType>) { emit('update:modelValue', 'input content') emit('submit') }
效果验证
这三种方案都能让TypeScript正确识别emit的调用规则,提供精准的事件名和参数智能提示,同时彻底消除报错,全程不需要用any类型。
内容的提问来源于stack exchange,提问作者CaptainCarl
相关产品推荐
相关产品推荐

