TypeScript泛型信息丢失问题求助:直接传实例时类型丢失
问题分析
问题根源在于两方面:
- 函数
F的泛型约束T extends Record<string, C<any, any>>过于宽泛,TypeScript无法精确推断每个C实例的泛型参数T,直接回退到any; - 在对象字面量中直接实例化
C时,TypeScript的上下文推断未保留最精确的泛型类型,而是默认使用了Type或any。
解决方案
方案1:优化函数F的类型定义(推荐)
通过条件类型直接提取C实例的泛型参数T,替代依赖g属性的类型推导,避免宽泛约束导致的类型丢失:
type Type = 't1' | 't2' type TypeTo<T extends Type> = T class C<T extends Type = Type, G = TypeTo<T>> { g?: T constructor(readonly p: { t: T }) { } } // 优化后的F函数 function F<U extends Record<string, C<any>>>(p: U) { return 0 as unknown as { [K in keyof U]: U[K] extends C<infer T> ? T : never } } // 测试:返回值类型为 { a1: "t1" } const c = F({ a1: new C({ t: 't1' } as const) })
这种方式直接通过C<infer T>捕获每个实例的具体泛型类型,即便TypeTo逻辑复杂也能稳定推导。
方案2:使用工厂函数创建C实例
通过工厂函数封装C的实例化过程,强制保留精确的泛型类型,避免对象字面量上下文的类型拓宽:
type Type = 't1' | 't2' type TypeTo<T extends Type> = T class C<T extends Type = Type, G = TypeTo<T>> { g?: T constructor(readonly p: { t: T }) { } } // 工厂函数,确保T的类型被精确推断 function createC<T extends Type>(p: { t: T }) { return new C(p) } function F<T extends Record<string, C<any, any>>>(p: T) { return 0 as unknown as { [K in keyof T]: Exclude<T[K]['g'], void> } } // 测试:返回值类型为 { a1: "t1" } const c = F({ a1: createC({ t: 't1' } as const) })
方案3:给C添加私有类型标记(无运行时开销)
在C类中添加一个仅用于类型推断的私有属性,帮助TypeScript更清晰地捕获泛型T:
type Type = 't1' | 't2' type TypeTo<T extends Type> = T class C<T extends Type = Type, G = TypeTo<T>> { g?: T // 仅用于类型推断,无运行时代码生成 declare private readonly _type: T constructor(readonly p: { t: T }) { } } function F<T extends Record<string, C<any>>>(p: T) { return 0 as unknown as { [K in keyof T]: T[K]['_type'] } } // 测试:返回值类型为 { a1: "t1" } const c = F({ a1: new C({ t: 't1' } as const) })
内容的提问来源于stack exchange,提问作者flycran
相关产品推荐
相关产品推荐

