RxJS of([])声明Observable时push报错如何解决
RxJS Observable 初始化与单元测试类型报错解决方案
问题复现
组件内初始定义RxJS数据流的写法:
items$ = of([]) as Observable<Item[]>; ngOnInit(){ this.items$ = this.httpService.getPokemonList(); }
单元测试执行时抛出类型错误:
component.items$.push({"slot": 1, "pokemon": {"name": "my test name pokemon", "url": "a url"}}); // Error: Property 'push' does not exist on type 'Observable<Item[]>'
错误根因
- 该报错和
of([]) as Observable<Item[]>的初始化写法无直接关联,核心问题是Observable 流对象本身不是数组,不存在push方法:items$的类型是「会发送Item[]类型数据的流」,流本身不具备数组的原生方法,这里混淆了「流发送的值类型」和「流自身的类型」。
组件侧正确声明方式
场景1:仅需初始空值、后续直接替换为接口返回流
不需要强制类型断言,直接声明类型即可,TS会自动推导of([])的类型匹配:
items$: Observable<Item[]> = of([]); ngOnInit(){ this.items$ = this.httpService.getPokemonList(); }
场景2:需要后续动态往数据集合里新增/修改值
不要用普通Observable,应该用BehaviorSubject作为内部可推送的数据源,对外暴露只读Observable防止外部随意篡改:
// 内部持有可手动推送值的Subject,初始值为空数组 private readonly _items$ = new BehaviorSubject<Item[]>([]); // 对外暴露只读流 public readonly items$: Observable<Item[]> = this._items$.asObservable(); ngOnInit(){ this.httpService.getPokemonList().subscribe(list => { this._items$.next(list); }) } // 封装新增条目的方法,内部通过next推送新的数组值 addPokemonItem(newItem: Item) { const currentList = this._items$.getValue(); this._items$.next([...currentList, newItem]); }
单元测试正确写法
直接对items$调用push是完全错误的用法,根据组件实现选择对应测试方式:
- 若为普通Observable直接绑定接口返回的场景:直接Mock HTTP服务的返回值即可,不需要手动操作
items$it('should load pokemon list after init', () => { const testMockList = [{"slot": 1, "pokemon": {"name": "my test name pokemon", "url": "a url"}}]; httpServiceMock.getPokemonList.and.returnValue(of(testMockList)); component.ngOnInit(); component.items$.subscribe(list => { expect(list).toEqual(testMockList); }); }); - 若为BehaviorSubject实现的动态更新场景:调用组件暴露的
addPokemonItem等更新方法,不要直接操作对外暴露的Observable实例。
内容的提问来源于stack exchange,提问作者Andrew Howard
相关产品推荐
相关产品推荐

