cxhl818 2025-09-25 14:49 采纳率: 40%
浏览 11
已结题

element控件封装后出现TypeScript 类型报错问题

使用vben admin,再次封装里面的element控件时出现了一些问题。
这是原本的代码:

<ElRadioGroup
                key="BarCodeTypeId"
                v-model="productInfoState.productInfo.BarCodeTypeId"
                @change="
                  (value) => {
                    const selected = fieldOptions.BarCodeTypeId!.find(
                      (item) => item.value === value,
                    );
                    productInfoState.productInfo.BarCodeTypeValue =
                      selected?.label || '';
                  }
                "
              >
                <ElRadio
                  v-for="option in fieldOptions.BarCodeTypeId"
                  :key="option.value"
                  :label="option.value"
                >
                  {{ option.label }}
                </ElRadio>
              </ElRadioGroup>


代码没有发生任何报错,单选框能正常使用。我将两个组件各自封装成了:

<script setup lang="ts">
import { ref, useSlots } from 'vue';

import { ElRadioGroup } from 'element-plus';

const slots = useSlots();
const elRadioGroupRef = ref<InstanceType<typeof ElRadioGroup>>();
defineExpose({
  elRadioGroupRef,
});
</script>

<template>
  <ElRadioGroup ref="elRadioGroupRef" v-bind="$attrs">
    <template v-for="(_value, name) in slots" #[name]="scope">
      <slot :name="name" v-bind="scope || {}"></slot>
    </template>
  </ElRadioGroup>
</template>



这时候原本代码的@change中出现报错参数“value”隐式具有“any”类型。单选框能够正常使用。怎么解决这个报错?

二编:
修改封装代码为

<script setup lang="ts">
import { ref, useSlots } from 'vue';

import { ElRadioGroup } from 'element-plus';

const emit = defineEmits<{
  (e: 'change', value: boolean | number | string | undefined): void;
  (e: 'update:modelValue', value: boolean | number | string | undefined): void;
}>();
const slots = useSlots();
const elRadioGroupRef = ref<InstanceType<typeof ElRadioGroup>>();

defineExpose({
  elRadioGroupRef,
});
</script>

<template>
  <ElRadioGroup
    ref="elRadioGroupRef"
    v-bind="$attrs"
    @change="
      (val: string | number | boolean | undefined) => emit('change', val)
    "
    @update:model-value="
      (val: string | number | boolean | undefined) =>
        emit('update:modelValue', val)
    "
  >
    <template v-for="(_value, name) in slots" #[name]="scope">
      <slot :name="name" v-bind="scope || {}"></slot>
    </template>
  </ElRadioGroup>
</template>


后,不再报错。我想知道为什么要转发两个事件而不是只转发change才能实现不报错

  • 写回答

3条回答 默认 最新

  • 檀越@新空间 2025-09-25 14:50
    关注

    下午好🌅🌅🌅
    本答案参考通义千问

    在使用 Vben Admin 框架时,如果你对 Element Plus 的组件(如 ElRadioGroup)进行了封装,并且在封装后的组件中使用了 @change 事件,但 TypeScript 报错提示参数 value 隐式具有 any 类型,这通常是因为你没有为 @change 事件定义正确的类型。


    问题分析

    你将 ElRadioGroup 封装成一个自定义组件后,在父组件中使用它时,调用:

    <CustomRadioGroup @change="value => { ... }" />
    

    但是 TypeScript 不知道 value 的类型,所以报错:
    Parameter 'value' implicitly has an 'any' type.

    这是因为你在封装组件时,没有明确地声明 @change 事件的参数类型。


    🔧 解决方案

    1. 定义自定义组件的 props 和 emits

    你需要在封装组件中定义 propsemits,尤其是 @change 事件的参数类型。

    2. 使用 Vue 3 的 definePropsdefineEmits

    <script setup> 中,使用 definePropsdefineEmits 来声明事件和属性。

    3. 修改你的封装组件代码如下:

    <script setup lang="ts">
    import { ref, useSlots } from 'vue';
    import { ElRadioGroup } from 'element-plus';
    
    // 声明 props(如果需要)
    const props = defineProps<{
      modelValue?: string | number; // 根据你的实际需求修改
    }>();
    
    // 声明 emits
    const emit = defineEmits<{
      (e: 'change', value: string | number): void;
    }>();
    
    const slots = useSlots();
    const elRadioGroupRef = ref<InstanceType<typeof ElRadioGroup>>();
    
    defineExpose({
      elRadioGroupRef,
    });
    </script>
    
    <template>
      <ElRadioGroup
        ref="elRadioGroupRef"
        v-model="props.modelValue"
        @change="emit('change', $event)"
        v-bind="$attrs"
      >
        <template v-for="(_value, name) in slots" #[name]="scope">
          <slot :name="name" v-bind="scope || {}"></slot>
        </template>
      </ElRadioGroup>
    </template>
    

    注意: 上面代码中 v-model="props.modelValue" 是为了兼容 v-model,如果你不需要绑定 modelValue,可以移除。


    🛠️ 修改后的父组件调用示例

    确保你在使用这个封装组件时,也正确传递 v-model 并监听 @change 事件:

    <template>
      <CustomRadioGroup
        v-model="productInfoState.productInfo.BarCodeTypeId"
        @change="
          (value) => {
            const selected = fieldOptions.BarCodeTypeId!.find(
              (item) => item.value === value,
            );
            productInfoState.productInfo.BarCodeTypeValue =
              selected?.label || '';
          }
        "
      >
        <template #default="{ label, value }">
          <ElRadio :label="value">{{ label }}</ElRadio>
        </template>
      </CustomRadioGroup>
    </template>
    

    📌 关键点总结

    • 使用 definePropsdefineEmits 明确类型
    • @change 中使用 emit('change', $event) 来传递值
    • 在父组件中确保 @change 的参数类型被正确识别

    最终解决效果

    通过以上修改,TypeScript 将能够正确识别 @change 事件的参数类型,不再出现 any 类型的警告。同时,组件仍然保持功能正常。


    如有其他封装组件的问题,也可以继续提问!

    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 10月13日
  • 修改了问题 9月25日
  • 创建了问题 9月25日