TypeScript中Extract<>未按预期工作?是我还是类型检查器出错?
问题确认:TypeScript类型检查器限制还是代码问题?
场景与代码实现
我想要构建一个Num类,要求传入的数字字符串名称和数字值必须匹配,不匹配时触发类型错误,示例如下:
const test1 = new Num("two", 2) // 正常通过 const test2 = new Num("two", 3) // 预期触发类型错误
为此我编写了以下类型定义和类:
type Numbers = { name: "two", type: 2 } | { name: "three", type: 3 } class Num<T extends Numbers["type"]> { value: T typeName: Extract<Numbers, { type: T }>["name"] constructor(typeName: Extract<Numbers, { type: T }>["name"], value: T) { this.value = value; this.typeName = typeName; // 此处出现类型错误 } }
出现的类型错误
Type 'Extract<{ name: "two"; type: 2; }, { type: T; }>["name"] | Extract<{ name: "three"; type: 3; }, { type: T; }>["name"]' is not assignable to type 'Extract<{ name: "two"; type: 2; }, { type: T; }>["name"] & Extract<{ name: "three"; type: 3; }, { type: T; }>["name"]'. Type 'Extract<{ name: "two"; type: 2; }, { type: T; }>["name"]' is not assignable to type 'Extract<{ name: "two"; type: 2; }, { type: T; }>["name"] & Extract<{ name: "three"; type: 3; }, { type: T; }>["name"]'. Type 'string' is not assignable to type 'Extract<{ name: "two"; type: 2; }, { type: T; }>["name"] & Extract<{ name: "three"; type: 3; }, { type: T; }>["name"]'. Type 'string' is not assignable to type 'Extract<{ name: "three"; type: 3; }, { type: T; }>["name"]'. Type '"two"' is not assignable to type '"three"'. Type 'Extract<{ name: "two"; type: 2; }, { type: T; }>["name"]' is not assignable to type 'Extract<{ name: "three"; type: 3; }, { type: T; }>["name"]'. Type 'Extract<{ name: "two"; type: 2; }, { type: T; }>' is not assignable to type 'Extract<{ name: "three"; type: 3; }, { type: T; }>'. Type '{ type: T; } & { name: "two"; type: 2; }' is not assignable to type 'Extract<{ name: "three"; type: 3; }, { type: T; }>'.
核心疑问
从逻辑上看,构造函数参数typeName和实例属性this.typeName的类型完全一致,赋值操作应该合法,但TypeScript却抛出了类型错误。我想确认:这是TypeScript类型检查器的问题,还是我的代码存在逻辑漏洞?(注:已有替代实现方案,无需提供解决方案)
结论
这是TypeScript类型检查器在处理泛型条件类型时的局限性,并非你的代码逻辑问题。
原因说明
当类的泛型参数T被用于条件类型Extract<Numbers, { type: T }>["name"]时,TypeScript的类型系统无法在构造函数内部精准追踪T对应的具体联合类型分支。它会将该条件类型解析为所有可能分支的交叉类型(即错误信息中的&操作符结果),因为检查器无法确定T到底对应Numbers中的哪一个成员,从而错误地判定typeName的类型与this.typeName不兼容。
本质上,TypeScript对泛型上下文里的条件类型的流分析能力还不完善,导致这种逻辑上完全合法的赋值被误判为类型不兼容。
内容的提问来源于stack exchange,提问作者Nearoo
相关产品推荐
相关产品推荐

