Node13升级至更高版本遇TS类型约束错误求助
Node版本升级后TypeScript泛型约束报错修复
问题背景
将项目从Node 13升级至Node 14及以上版本后,以下代码出现TypeScript编译错误:
目标函数代码
export function ConstructNotificationsObservable<TKVMap extends KeyValueMapGenericConstraint<TKVMap>>( instance: INotificationsObservable<TKVMap>, context: IObservableContext<KeyValueMapToNotifications<TKVMap>>, create?: (context: INotificationsObservableContext<TKVMap>) => TNotificationsObservableHook<TKVMap> | void ): void { ConstructClassWithPrivateMembers(instance, NOTIFICATIONS_OBSERVABLE_PRIVATE); const privates: INotificationsObservablePrivate<TKVMap> = (instance as INotificationsObservableInternal<TKVMap>)[NOTIFICATIONS_OBSERVABLE_PRIVATE]; privates.context = context; privates.observersMap = new Map<KeyValueMapKeys<TKVMap>, KeyValueMapToNotificationsObservers<TKVMap>[]>(); privates.othersObservers = []; InitObservableHook( instance, privates, NewNotificationsObservableContext, create, ); }
关联类型声明
export type KeyValueMapGenericConstraint<TKVMap extends object> = KeyValueMapConstraint<TKVMap, KeyValueMapGeneric>;
编译错误信息
TS2313: Type parameter 'TKVMap' has a circular constraint.TS2344: Type 'TKVMap' does not satisfy the constraint 'object'.
函数调用方式:
ConstructNotificationsObservable<TKVMap>(this, context, create);
错误原因
Node 14及以上版本默认搭配的TypeScript版本(如TS 4.x及后续版本)对泛型约束的循环引用检查更严格,而Node 13对应的旧版TS允许这种间接循环约束写法。当前代码中TKVMap extends KeyValueMapGenericConstraint<TKVMap>形成了循环约束,且TS无法推断TKVMap满足object类型要求。
修复方案
方案1:直接替换为底层约束类型
如果KeyValueMapGenericConstraint的本质是约束TKVMap为键值对结构且值符合KeyValueMapGeneric类型,可直接将泛型约束改为Record<string, KeyValueMapGeneric>,同时自动满足object约束:
export function ConstructNotificationsObservable<TKVMap extends Record<string, KeyValueMapGeneric>>( instance: INotificationsObservable<TKVMap>, context: IObservableContext<KeyValueMapToNotifications<TKVMap>>, create?: (context: INotificationsObservableContext<TKVMap>) => TNotificationsObservableHook<TKVMap> | void ): void { // 原有代码逻辑不变 }
方案2:拆分约束打破循环
如果KeyValueMapGenericConstraint包含复杂逻辑无法直接替换,可先约束TKVMap为object,再通过交叉类型确保符合具体约束:
// 先调整KeyConstraint类型声明,添加条件判断避免循环 export type KeyValueMapGenericConstraint<T> = T extends object ? KeyValueMapConstraint<T, KeyValueMapGeneric> : never; // 修改函数泛型约束 export function ConstructNotificationsObservable<TKVMap extends object>( instance: INotificationsObservable<TKVMap & KeyValueMapGenericConstraint<TKVMap>>, context: IObservableContext<KeyValueMapToNotifications<TKVMap>>, create?: (context: INotificationsObservableContext<TKVMap>) => TNotificationsObservableHook<TKVMap> | void ): void { // 原有代码逻辑不变 }
方案3:简化约束层级
直接将KeyValueMapGenericConstraint的约束逻辑合并到函数泛型中,去掉中间类型的循环依赖:
export function ConstructNotificationsObservable<TKVMap extends KeyValueMapConstraint<TKVMap, KeyValueMapGeneric> & object>( instance: INotificationsObservable<TKVMap>, context: IObservableContext<KeyValueMapToNotifications<TKVMap>>, create?: (context: INotificationsObservableContext<TKVMap>) => TNotificationsObservableHook<TKVMap> | void ): void { // 原有代码逻辑不变 }
验证
修改后重新编译代码,两个TypeScript错误会被消除,同时保留原有业务逻辑。
内容的提问来源于stack exchange,提问作者George Salukvadze
相关产品推荐
相关产品推荐

