如何给封装combineLatest的自定义函数配置正确的TypeScript类型?
类型优化方案
可以通过 TypeScript 泛型 + 函数重载的方式匹配原生 combineLatest 的类型推导规则,完整保留输入源的静态类型:
优化思路
- 定义两个函数重载分别匹配「单个Observable入参」和「Observable数组入参」两种调用场景
- 用泛型动态捕获输入source的所有Observable的发射值类型
- 最终返回值类型自动将
observeAnimal$返回的Animal类型拼接在combineLatest结果元组的最后一位,和原生combineLatest行为完全一致
完整优化代码
import { Observable, combineLatest } from 'rxjs'; enum Animals { DOG, CAT } interface Animal { name: string, type: Animals } export function observeAnimal$(type: Animals): Observable<Animal> { // 实现逻辑 } // 重载1:入参为单个Observable的场景 export function combineAnimal$<T>(source: Observable<T>, type: Animals): Observable<[T, Animal]> // 重载2:入参为Observable数组的场景(TS4.0+ 可变元组泛型支持,可精准推导元组类型) export function combineAnimal$<T extends Observable<any>[]>(source: [...T], type: Animals): Observable<[...{[K in keyof T]: T[K] extends Observable<infer U> ? U : never}, Animal]> // 函数实现 export function combineAnimal$(source: Observable<any>[] | Observable<any>, type: Animals) { if(Array.isArray(source)) { return combineLatest([...source, observeAnimal$(type)]); } else { return combineLatest([source, observeAnimal$(type)]); } }
使用效果示例
import { of } from 'rxjs'; // 单源调用场景 const user$ = of({id: 1, nickname: '阿明'}); const singleResult$ = combineAnimal$(user$, Animals.DOG); // 自动推导类型:Observable<[{id: number; nickname: string}, Animal]> singleResult$.subscribe(([user, animal]) => { // 此处user和animal都有完整的类型提示,不会丢失类型 }) // 数组源调用场景 const sourceList = [of(2023), of('测试文本'), of(true)] as const; const arrResult$ = combineAnimal$(sourceList, Animals.CAT); // 自动推导类型:Observable<[number, string, boolean, Animal]>
低版本TS兼容方案
如果你的TypeScript版本低于4.0,不支持可变元组泛型,可以使用简化的数组类型推导:
// 低版本TS重载2写法,返回联合类型数组 export function combineAnimal$<T>(source: Observable<T>[], type: Animals): Observable<(T | Animal)[]>
这种写法不能精准推导每个位置的类型,但也比any类型更安全。
内容的提问来源于stack exchange,提问作者Matteo Veraldi
相关产品推荐
相关产品推荐

