You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

TypeScript泛型信息丢失问题求助:直接传实例时类型丢失

问题分析

问题根源在于两方面:

  1. 函数F的泛型约束T extends Record<string, C<any, any>>过于宽泛,TypeScript无法精确推断每个C实例的泛型参数T,直接回退到any;
  2. 在对象字面量中直接实例化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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.30 00:15:05