Vue3升级中多Emits重复定义触发TS1117错误的解决方法
解决方案
错误原因
你触发的An object literal cannot have multiple properties with the same name.ts(1117)错误,本质是JavaScript/TypeScript的对象不允许重复定义同名属性——你在defineComponent的配置对象里写了两次emits和两次setup,这违反了对象的语法规则。
具体修复步骤
- 合并自定义事件声明:把所有需要触发的自定义事件名放在同一个
emits数组中,不要拆分多次声明。 - 合并setup逻辑:将两个
setup函数里的方法和逻辑合并到同一个setup中,通过emit统一触发事件。 - 修正响应式变量:
showDeleteAddressConfirmation需要声明为响应式变量,Vue3中可以用ref实现。 - 统一代码风格:尽量避免选项式API(methods、props等)和组合式API(setup)混用,推荐使用更简洁的
<script setup>语法。
修复后的代码示例
这里用Vue3推荐的<script setup lang="ts">语法改写,逻辑更清晰:
<script setup lang="ts"> import { ref } from 'vue'; import { DataTableActionTypes } from '@/shared/enums/dataTableActionTypes.enum'; import Modal from '@/shared/components/modal/Modal.vue'; // 声明组件接收的props interface Props { item?: any; // 对应原Vue2的any类型 } const props = defineProps<Props>(); // 声明组件触发的自定义事件 interface Emits { (e: 'action', data: any, type: DataTableActionTypes): void; (e: 'delete-address', id: number, type: DataTableActionTypes): void; } const emit = defineEmits<Emits>(); // 响应式变量 const showDeleteAddressConfirmation = ref(false); // 事件处理方法 const onDeleteAddressClick = () => { showDeleteAddressConfirmation.value = true; emit('action', props.item, DataTableActionTypes.ActionButtonSelect); }; const onCloseDelete = () => { showDeleteAddressConfirmation.value = false; emit('action', props.item, DataTableActionTypes.ResetActionButtton); }; const deleteAddress = () => { showDeleteAddressConfirmation.value = false; emit('delete-address', props.item, DataTableActionTypes.Delete); }; </script>
如果你更倾向于保留选项式API的写法,修复后的代码如下:
<script lang="ts"> import { defineComponent, ref } from 'vue'; import { DataTableActionTypes } from '@/shared/enums/dataTableActionTypes.enum'; import Modal from '@/shared/components/modal/Modal.vue'; export default defineComponent({ name: 'AddressListActionButtons', components: { Modal }, props: { item: { type: Object as () => any, // 声明any类型的正确方式 default: null } }, // 合并后的自定义事件声明 emits: ['action', 'delete-address'], setup(props, { emit }) { const showDeleteAddressConfirmation = ref(false); const onAction = (data: any, type: DataTableActionTypes) => { emit('action', data, type); }; const onDeleteAddress = (id: number, type: DataTableActionTypes) => { emit('delete-address', id, type); }; // 将方法和响应式变量暴露给模板 return { showDeleteAddressConfirmation, onAction, onDeleteAddress }; }, methods: { onDeleteAddressClick() { this.showDeleteAddressConfirmation = true; this.onAction(this.item, DataTableActionTypes.ActionButtonSelect); }, onCloseDelete() { this.showDeleteAddressConfirmation = false; this.onAction(this.item, DataTableActionTypes.ResetActionButtton); }, deleteAddress() { this.showDeleteAddressConfirmation = false; this.onDeleteAddress(this.item, DataTableActionTypes.Delete); } } }); </script>
关键说明
- 选项式API中,
props的type不能直接写undefined,如果要表示任意类型,用Object as () => any或者直接any。 - 组合式API中,
defineProps和defineEmits是Vue3提供的编译器宏,不需要导入就能使用,用于类型安全地声明props和事件。 - 无论哪种写法,同一个配置对象里不能重复定义同名属性,这是JS/TS的基础语法规则。
内容的提问来源于stack exchange,提问作者Kanchana Kariyawasam
相关产品推荐
相关产品推荐

