TS开启strict模式下带RxJS Subject的泛型类赋值为unknown报错如何解决?
报错核心原因
这个报错是TypeScript的型变规则和RxJS Subject的特性共同导致的,属于TS提前拦截后续非法操作的防护检查,和你当前写的赋值操作的表面逻辑无关:
- TS的泛型存在协变、逆变两种兼容规则:如果泛型参数
T出现在方法的返回值位置(生产者场景),属于协变位点,符合你认知的「具体类型可以赋值给unknown类型」规则;如果T出现在方法的入参位置(消费者场景),属于逆变位点,兼容规则完全反过来——只有父类型可以赋值给子类型,子类型不能赋值给父类型。 - RxJS的
Subject<T>同时实现了Observable<T>和Observer<T>两个接口:Observable<T>的T是返回值位置,属于协变位点,Observable<string>确实可以赋值给Observable<unknown>Observer<T>的T是next(value: T)方法的入参位置,属于逆变位点,因此Observer<string>不能赋值给Observer<unknown>
- 报错最后一行的提示对应的是潜在风险:如果TS允许你把
Example<string>赋值给Example<unknown>类型的变量,后续你就可以合法调用example.events.next(true)(Example<unknown>的events的next接收unknown类型的入参),等于把unknown类型的值传给了原本只接受string的next方法,本质就是把unknown赋值给string,TS是在提前拦截这种后续可能出现的非法操作。 - 删除events属性后不报错的原因:当
T没有被类的任何成员使用时,TS的结构类型系统会认为所有Example<any>都是兼容的,自然不会触发泛型兼容性检查。
可行的修复方案
- 方案一(推荐,符合RxJS封装最佳实践):对外只暴露Observable能力,消除逆变位点
import { Subject, Observable } from 'rxjs'; class Example<T> { private readonly _events = new Subject<T>(); // 只对外暴露协变的Observable类型 readonly events: Observable<T> = this._events.asObservable(); constructor(x: T) { } }
修改后原赋值操作不会再报错。
- 方案二(TS 4.7及以上版本支持):显式声明泛型协变
如果你确实需要对外暴露Subject的完整能力,可以用out修饰符声明泛型T是协变的,这会让TS跳过逆变位点的检查,需要你自行保证不会对events进行非法的next调用:
class Example<out T> { readonly events = new Subject<T>(); constructor(x: T) { } }
- 方案三(临时兼容):用类型断言绕过检查
example = new Example('some string') as Example<unknown>; example = new Example(123) as Example<unknown>;
内容的提问来源于stack exchange,提问作者Sam Herrmann
相关产品推荐
相关产品推荐

