Angular子组件调用emit报错void类型不存在length属性
问题背景
在Angular项目中开发子组件slide1.component.ts,组件代码如下:
import { Component, Input, OnInit, EventEmitter, Output } from '@angular/core'; @Component({ selector: 'app-slide1', templateUrl: './slide1.component.html', styleUrls: ['./slide1.component.css'], }) export class Slide1Component implements OnInit { @Input() select_option: string; @Output('answer') answer: EventEmitter<{ Res: any; Ans: any; }> = new EventEmitter(); constructor() {} ngOnInit() {} callchild() { var res = this.answer.emit({ Res: '', Ans: '' }); console.log(res.length); console.log('child '); } }
在callchild方法中,将this.answer.emit({ Res: '', Ans: '' })的返回值赋值给res变量,尝试访问res.length时触发TypeScript报错:
Property 'length' does not exist on type 'void'.
已知父组件中绑定到answer事件的处理方法会返回数组类型结果,相同逻辑直接在父组件方法内调用时可正常运行,但在子组件中调用时就出现上述错误。
报错原因
Angular的EventEmitter.emit()方法本身返回类型为void,不会返回父组件事件处理函数的执行结果。
Angular的组件事件通信是单向通知逻辑:子组件调用emit仅负责向父组件发送事件载荷,父组件接收到事件后执行的处理函数返回值,不会反向传递给子组件的emit调用处,因此TS会判定res是void类型,访问length属性自然会报类型错误。
解决方案
不要依赖emit()的返回值获取父组件处理结果,可以根据业务场景选择以下实现方式:
- 方式1:通过
@Input传入回调函数
父组件将事件处理逻辑包装为函数,通过Input属性传给子组件,子组件直接调用该函数即可拿到返回结果,适合简单的同步返回场景。
实现示例:- 子组件新增接收回调的Input属性:
@Input() answerHandler: (payload: {Res: any, Ans: any}) => any[];- 父组件模板中绑定回调方法:
<app-slide1 [answerHandler]="processAnswer"></app-slide1>- 父组件中实现处理逻辑:
processAnswer(payload: {Res: any, Ans: any}): any[] { // 原有业务逻辑,最终返回数组结果 return []; }- 子组件中替换原有emit逻辑:
callchild() { const res = this.answerHandler({ Res: '', Ans: '' }); console.log(res.length); // 类型校验正常,可正常访问length属性 console.log('child '); } - 方式2:通过服务共享状态
对于跨多层组件、逻辑复杂的场景,可以创建共享服务存储处理结果,父子组件都注入该服务,父组件处理完事件后将结果写入服务,子组件从服务中读取结果即可。 - 方式3:Input+Output双向通信
子组件通过Output抛出事件后,父组件处理完成,再通过Input属性将结果传回子组件,子组件通过ngOnChanges监听Input变化获取结果,适合常规的父子组件数据同步场景。
内容的提问来源于stack exchange,提问作者user3653474
相关产品推荐
相关产品推荐

