组件部分代码:

src\components\common\WorkflowMainDialog.vue

interface Props {
  /** 对话框标题 */
  title?: string;
  /** 活动实例(包含必要信息) */
  activityInstance: ActivityInstance;
  /** 校验数据(返回 false 或 reject 则return) */
  validate?: () => boolean | Promise<boolean>;
  /** 保存函数(接收一个 done 回调,保存完成后调用) */
  onSave?: (done: () => void) => void | Promise<void>;
}
const props = withDefaults(defineProps<Props>(), {
  title: "流程办理",
  validate: undefined,
  onSave: undefined
});

const emit = defineEmits<{
  /**
   * 已办理(办理/退回后)
   */
  audited: [];
  /**
   * 保存(已通过 onSave 处理,此事件可作为额外通知)
   */
  save: [];
}>();

 defineProps定义了onSave,defineEmits定义了save,造成命名冲突

使用组件

    <WorkflowMainDialog
      v-if="store.currentCapitalAllocate?.activityInstance"
      ref="capitalAllocateWorkflowInstanceDialogRef"
      title="资金分配"
      :activity-instance="store.currentCapitalAllocate?.activityInstance"
      :validate="validateAllocate"
      :onSave="handleSaveAllocate"
      @audited="handleAudited">

报错如下:

不能将类型“(done: () => void) => Promise<void>”分配给类型“((done: () => void) => void | Promise<void>) & (() => any)”。
  不能将类型“(done: () => void) => Promise<void>”分配给类型“() => any”。
    目标签名提供的自变量太少。预期为 1 个或更多,但实际为 0 个。ts-plugin(2322)
WorkflowMainDialog.vue(40, 3): 所需类型来自属性 "onSave",在此处的 "{ readonly title?: string | undefined; readonly activityInstance: ActivityInstance; readonly loading?: boolean | undefined; readonly isModified?: boolean | undefined; ... 5 more ...; readonly onAudited?: (() => any) | undefined; } & VNodeProps & AllowedComponentProps & ComponentCustomProps & Record<...>" 类型上声明该属性
通义灵码一键修复

(property) onSave?: (((done: () => void) => void | Promise<void>) & (() => any)) | undefined
保存函数(接收一个 done 回调,保存完成后调用)

您遇到的类型错误确实是由于 defineEmits 中声明了 save 事件,导致 Vue 自动生成一个同名的 onSave prop(类型为 () => any),与您在 defineProps 中自定义的 onSave(类型 (done: () => void) => void | Promise<void>)合并为交叉类型,无法兼容。

即使父组件没有使用 @save,类型系统仍然会认为组件可能接收这个 prop,因此冲突依然存在。

解决方案

1. 修改自定义 prop 名称(推荐)

将 onSave 改为不与事件监听器冲突的名称,例如 saveHandler

修改组件内部:

ts

interface Props {
  // ...
  /** 保存函数(接收一个 done 回调,保存完成后调用) */
  saveHandler?: (done: () => void) => void | Promise<void>; // 改名
}

// 使用处
const buttonSaveDisabled = computed(
  () => props.loading || auditLoading.value || props.saving || !props.isModified || !props.saveHandler
);

const handleSaveWithDone = async (event?: MouseEvent, done?: () => void) => {
  if (props.saveHandler) {
    await props.saveHandler(() => {
      done?.();
      emit("save"); // 可选,仍可触发 save 事件
    });
  } else {
    done?.();
  }
};

模板中:

vue

<BasePreventReClickButtonEmit
  v-if="saveHandler"
  class="short-btn"
  type="primary"
  plain
  :disabled="buttonSaveDisabled"
  :timeout="0"
  @click="handleSaveWithDone"
>
  保存
</BasePreventReClickButtonEmit>

父组件使用时:

vue

<WorkflowMainDialog
  ...
  :save-handler="handleSaveAllocate"
  @audited="handleAudited"
  @save="onSaveComplete"  <!-- 可选 -->
>

2. 如果不需要 save 事件,可以从 defineEmits 中移除

ts

const emit = defineEmits<{
  audited: [];
  // 移除 save 事件
}>();

但保留事件有时是有用的,比如父组件想监听保存完成做额外操作。因此方案 1 更灵活。

为什么必须改名?

因为 Vue 的 <script setup> 会自动为 defineEmits 中声明的事件生成对应的 props(命名规则 onXxx),类型为 ((...args: any[]) => any) | undefined。这些 props 会与您在 defineProps 中声明的同名的 prop 合并,导致 TypeScript 要求您的 prop 同时满足两种签名。

改名后,自定义 prop saveHandler 与自动生成的 onSave 不再冲突,问题解决。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐