Vue.js 2.7 script setup中defineEmits传入组合式函数的TS问题
问题根源
这完全是TypeScript类型不兼容导致的,和运行时逻辑无关——Vue 2.7对script setup里的defineEmits做了严格的类型强化,返回的emit函数是绑定了你声明的事件列表的严格类型;而选项式API的setup参数里的emit是宽松的(event: string, ...args: any[]) => void类型,自然能兼容你的组合式函数useIcomActCompatibility的参数要求。
举个具体例子:
如果你在script setup里这样声明emits:
const emit = defineEmits<{ 'icon-click': [id: string] }>()
此时emit的类型是(e: 'icon-click', id: string) => void,只能触发icon-click事件且参数必须是string类型;但你的组合式函数如果接受的是(event: string, ...args: any[]) => void这种宽松类型,TS就会抛出TS2322错误,因为严格类型无法赋值给宽松类型(反过来则可以)。
解决方法
根据你的需求选对应的方案:
方案1:给组合式函数绑定严格的emit类型
把组件里defineEmits返回的emit类型传递给组合式函数,保证类型完全匹配:// 组件内 const emit = defineEmits<{ 'icon-click': [id: string] }>() // 组合式函数 type IconEmit = typeof emit export function useIcomActCompatibility(emit: IconEmit) { // 逻辑代码 }方案2:放宽组合式函数的emit参数类型
如果组合式函数是通用型的,不想绑定特定组件的事件列表,可以用Vue内置的EmitFn类型或者手动声明宽松类型:import type { EmitFn } from 'vue' // 或者手动定义:type EmitFn = (event: string, ...args: any[]) => void export function useIcomActCompatibility(emit: EmitFn) { // 逻辑代码 } // 组件内调用时用类型断言 useIcomActCompatibility(emit as EmitFn)方案3:关闭严格emit类型检查(不推荐)
在tsconfig.json里禁用Vue的严格emit类型校验,这样defineEmits返回的emit会和选项式API的emit类型一致:{ "compilerOptions": { // 你的其他配置 }, "vueCompilerOptions": { "strictEmits": false } }注意:这种方式会失去TS对emit事件的类型保护,不建议在大型项目中使用。
内容的提问来源于stack exchange,提问作者F.A.M.

