使用条件类型推断泛型返回unknown问题排查
TypeScript泛型子类类型推断问题解决方案
问题场景
当尝试从泛型父类E<Output>的子类C<Optional>中推断Output类型时,使用条件类型Func<T extends E<any>>会返回unknown,但直接传入E的实例却能正确推断类型:
class E<Output> {} class C<Optional extends boolean> extends E<Optional extends true ? { a: string } : { b: string }> {} type Func<T extends E<any>> = T extends E<infer Output> ? Output : never type Y1 = Func<C<true>> // 实际:unknown,预期:{ a: string } type Y2 = Func<C<false>> // 实际:unknown,预期:{ b: string } type Y3 = Func<E<{ c: string }>> // 正确,实际:{ c: string },预期:{ c: string }
问题原因
TypeScript的条件类型推断机制不会自动追踪子类泛型参数与父类类型参数的关联逻辑。C<Optional>继承的E类型依赖于自身的泛型参数Optional,但这种关联并未被TypeScript视为可直接推断的信息,因此在执行T extends E<infer Output>时,无法解析出具体的Output类型,只能返回unknown。
解决方案
方案1:父类显式暴露Output类型
在父类E中定义类型别名,让所有子类自动继承该类型,直接通过索引访问获取Output:
class E<Output> { // 定义类型别名,子类自动继承 type Output = Output; } class C<Optional extends boolean> extends E<Optional extends true ? { a: string } : { b: string }> {} // 直接通过索引访问子类继承的Output类型 type Func<T extends E<any>> = T['Output']; type Y1 = Func<C<true>> // { a: string } type Y2 = Func<C<false>> // { b: string } type Y3 = Func<E<{ c: string }>> // { c: string }
方案2:针对子类单独处理条件类型
如果不需要兼容所有E的子类,可直接在Func中针对C的泛型参数进行推断:
class E<Output> {} class C<Optional extends boolean> extends E<Optional extends true ? { a: string } : { b: string }> {} type Func<T> = // 先匹配C的实例,从泛型参数推断Output T extends C<infer Optional> ? (Optional extends true ? { a: string } : { b: string }) : // 再匹配E的实例,常规推断 T extends E<infer Output> ? Output : never type Y1 = Func<C<true>> // { a: string } type Y2 = Func<C<false>> // { b: string } type Y3 = Func<E<{ c: string }>> // { c: string }
方案3:子类显式声明Output类型
在子类C中单独定义Output类型别名,确保条件类型能直接捕获:
class E<Output> {} class C<Optional extends boolean> extends E<Optional extends true ? { a: string } : { b: string }> { type Output = Optional extends true ? { a: string } : { b: string }; } // 优先读取子类自身的Output类型,再回退到父类推断 type Func<T extends E<any>> = T extends { Output: infer O } ? O : T extends E<infer O> ? O : never; type Y1 = Func<C<true>> // { a: string } type Y2 = Func<C<false>> // { b: string } type Y3 = Func<E<{ c: string }>> // { c: string }
内容的提问来源于stack exchange,提问作者kennarddh
相关产品推荐
相关产品推荐

