You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue3动态组件TypeScript类型报错:如何正确定义类型?

Vue3动态组件的类型标注问题

组件代码示例

Child.vue

<script lang='ts' setup>
// 省略部分代码

const emit = defineEmits<{
    (e: 'formErrors', errors: ValidationErrorsType): void,
    (e: 'formSuccess', success: boolean): void
}>()

// 省略部分代码

const submit = () => {
    // 省略部分代码
    emit('formErrors', errors);
}
</script>
<!-- 省略其余代码 -->

Parent.vue

<script lang='ts' setup>
const formErrors = ref<ValidationErrorsType>({});
const setFormErrors = (errors: ValidationErrorsType) => {
    formErrors.value = errors
}
</script>

<template>
    <component :is='Child' @form-errors='setFormErrors'/>
</template>

报错信息

[vue-tsc] Type '(errors: ValidationErrorsType) => void' is not assignable to type '(...args: unknown[]) => void'. Types of parameters 'errors' and 'args' are incompatible. Type 'unknown' is not assignable to type 'Record<string, string>'.

临时现象

保持setFormErrors的参数类型定义时,报错会消失:

const setFormErrors = (errors: ValidationErrorsType) => {
    formErrors.value = errors
}

问题

能否为Vue3动态组件正确设置类型?


答案:可以,以下是几种可行方案

问题根源是Vue动态组件的默认类型为Component,其事件回调参数会被推断为unknown,导致类型不匹配。我们可以通过以下方式让TypeScript识别组件的具体事件类型:

方案1:为动态组件断言具体类型

在脚本中声明子组件的实例类型,再在模板中为动态组件做类型断言,让TS识别其事件定义:

<script lang='ts' setup>
import Child from './Child.vue';
import type { ComponentPublicInstance } from 'vue';

// 声明Child组件的实例类型,包含其emits定义
type ChildInstance = ComponentPublicInstance<{}, {}, {}, {}, typeof Child['emits']>;

const formErrors = ref<ValidationErrorsType>({});
const setFormErrors = (errors: ValidationErrorsType) => {
    formErrors.value = errors
}
</script>

<template>
    <component :is='Child as ChildInstance' @form-errors='setFormErrors'/>
</template>

方案2:直接在事件回调中指定参数类型

在模板绑定事件时,显式指定回调参数的类型,跳过TS的默认推断:

<template>
    <component :is='Child' @form-errors='(errors: ValidationErrorsType) => formErrors.value = errors'/>
</template>

方案3:导出并复用子组件的Emits类型

在子组件中导出事件类型,父组件导入后用该类型约束回调函数:

// Child.vue
<script lang='ts' setup>
// 导出事件类型
export type ChildEmits = {
    (e: 'formErrors', errors: ValidationErrorsType): void,
    (e: 'formSuccess', success: boolean): void
}

const emit = defineEmits<ChildEmits>()
// 省略其余代码
</script>
// Parent.vue
<script lang='ts' setup>
import Child from './Child.vue';
import type { ChildEmits } from './Child.vue';

const formErrors = ref<ValidationErrorsType>({});
// 用ChildEmits约束回调函数的参数类型
const setFormErrors: (errors: Parameters<ChildEmits[0]>[1]) => void = (errors) => {
    formErrors.value = errors
}
</script>

<template>
    <component :is='Child' @form-errors='setFormErrors'/>
</template>

以上方案均可解决动态组件的类型不匹配问题,让TS正确校验事件回调的参数类型。

内容的提问来源于stack exchange,提问作者Evgeny Anisimov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 10:35:56