TypeScript函数重载结合Observable<T|T[]>如何去除as类型断言
解决方案
问题根因
- 原有重载的入参类型完全一致,TypeScript 无法根据入参值匹配对应的重载签名,导致返回值永远只能被推导为
Observable<T | T[]>,必须手动断言才能使用数组方法 - 原
Test类实例化时泛型传入了string | string[]属于多余写法,泛型 T 只需定义单个元素的类型即可,数组类型由重载签名控制返回
简化示例修改代码
通过把入参标记为字符串字面量类型,让 TypeScript 可以根据传入的具体参数值匹配对应重载,自动推导返回类型:
import { Observable } from 'rxjs'; class Test<T> { // 入参为字面量'foo'时返回单个Observable<T> test(flag: 'foo'): Observable<T>; // 入参为字面量'bar'时返回Observable<T[]> test(flag: 'bar'): Observable<T[]>; test(flag: string): Observable<T | T[]> { if (flag === 'foo') { return new Observable<T>(); } return new Observable<T[]>(); } } // 泛型仅传入单个元素类型即可 const test = new Test<string>(); // 自动推导为Observable<string> test.test('foo'); // 自动推导为Observable<string[]>,无需手动断言 test.test('bar').subscribe(foo => foo.map(bar => bar));
Angular 实际场景修改代码
我们可以扩展原有配置接口,新增标记位区分返回值是单个对象还是数组,通过重载绑定标记位和返回值类型:
import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { OptionWithBodyInterface } from './common.interface'; import { CommonService } from './common.service'; import { MethodType } from './common.type'; import { createUrl } from './helper'; // 扩展原有配置接口,新增isList标记位 interface RequestOption extends OptionWithBodyInterface { isList?: boolean; } @Injectable() export class RequestService<T> extends CommonService { // 重载1:isList显式为true时返回数组 public request(method : MethodType, options: RequestOption & { isList: true }) : Observable<T[]>; // 重载2:isList为false或者不传时返回单个对象 public request(method : MethodType, options?: RequestOption & { isList?: false }) : Observable<T>; public request(method : MethodType, options?: RequestOption) : Observable<T | T[]> { return this.http.request<T | T[]>(method, createUrl(this.getApiUrl(), this.getEndpoint()), { ...this.getOptions(), ...options }); } }
调用示例:
// 返回Observable<User>,无需断言 const user$ = requestService.request<User>('GET', { url: '/user/1' }); // 返回Observable<User[]>,无需断言 const userList$ = requestService.request<User>('GET', { url: '/user', isList: true }); userList$.subscribe(list => list.map(item => item.id)); // 类型自动推导正确,数组方法可直接调用
内容的提问来源于stack exchange,提问作者user924017
相关产品推荐
相关产品推荐

