TypeScript泛型异常:调用set方法时类型被推断为never
TypeScript类型推断异常:set方法参数被推断为never的原因与解决
问题原因
TypeScript将set方法参数推断为never,本质是递归类型ObjectItem与带约束的条件类型DynamicItem组合导致的类型解析异常:
- 原定义中
DynamicItem带有泛型约束T extends ObjectItem|Primitive,而ObjectItem是递归的对象类型({[k: string]: ObjectItem|Primitive})。 - 当
T为boolean这类原始类型时,TypeScript在解析T extends ObjectItem的条件判断时,递归类型的复杂性干扰了类型推断逻辑,导致PrimitiveItemInterface<T>中的泛型参数T被错误解析为never,最终让set方法的参数类型变成never。
解决方案
方案1:移除冗余的泛型约束
由于T的范围已经由ObjectItem的属性类型天然保证(只能是ObjectItem或Primitive),无需额外给DynamicItem和PrimitiveItemInterface添加泛型约束,让条件类型能准确匹配分支:
export type Primitive = boolean | string; export type ObjectItem = { [k: string]: ObjectItem | Primitive }; export type DynamicItem<T> = T extends ObjectItem ? ObjectItemInterface<T> : PrimitiveItemInterface<T>; export interface PrimitiveItemInterface<T> { value(): T; set(v: T): void; } export interface ObjectItemInterface<T extends ObjectItem> extends PrimitiveItemInterface<T> { get<K extends keyof T>(k: K): DynamicItem<T[K]>; } const example: ObjectItemInterface<{ enabled: boolean }> = null; example.get('enabled').set(true); // 类型推断正确,无报错
方案2:用内置object类型简化条件判断
避免递归类型ObjectItem干扰条件判断,改用TypeScript内置的object类型区分对象与原始类型,同时给PrimitiveItemInterface添加更精确的约束:
export type Primitive = boolean | string; export type ObjectItem = Record<string, ObjectItem | Primitive>; export type DynamicItem<T> = T extends object ? ObjectItemInterface<T & ObjectItem> : PrimitiveItemInterface<T>; export interface PrimitiveItemInterface<T extends Primitive> { value(): T; set(v: T): void; } export interface ObjectItemInterface<T extends ObjectItem> extends PrimitiveItemInterface<T> { get<K extends keyof T>(k: K): DynamicItem<T[K]>; } const example: ObjectItemInterface<{ enabled: boolean }> = null; example.get('enabled').set(true); // 类型推断正确
内容的提问来源于stack exchange,提问作者Snezhig
相关产品推荐
相关产品推荐

