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

为何TypeScript中`T extends B`无法在后续引用中限制T类型?

TypeScript泛型类型窄化失效的场景探究

PickedAttributeSimpler是一个带参数的泛型类型,其参数通过extends限制为极小集合——示例中仅'Moon'一种可能,但限制范围不一定这么窄。

原本预期,后续引用该泛型类型时,泛型参数会自动窄化为extends右侧指定的类型,特定场景下甚至能更窄。但在这个示例及多个简化后的复杂场景中,只有把泛型参数直接替换为extends右侧的类型,TypeScript才能正确推断出整个泛型的类型,符合预期行为。

但实际场景中,有时需要保留泛型参数:当类型实例指定的参数比限制类型更具体时,必须持续引用泛型参数来保持一致性——因此直接弃用泛型参数并非通用解决方案。

我想搞清楚,在哪些条件下,泛型参数的类型限制无法让后续引用自动体现窄化效果。

另外,有独立问题讨论过为何本示例中的部分简化方案(比如硬编码ObjectModelMap,或是在ObjectModel中使用条件类型)无法复现当前问题。

这可能是TypeScript的bug导致的,我找到最接近的issue是#33014,但它主要聚焦于函数而非其他类型定义。或许是我对问题的理解不到位,导致找不到正确的关键词搜索,也没法提交准确的报告(如果合适且不重复,欢迎提交新的bug报告)。


示例代码

import BN from "bn.js";

// 外部固定模型的简化版本;为简化示例省略了很多字段
type FieldNameWithValueMap = {
    Moon: [fieldName: "visibleStarsCount", fieldValue: BN] | [fieldName: "hostStar", fieldValue: string];
    Planet: [fieldName: "visibleStarsCount", fieldValue: BN] | [fieldName: "hostPlanet", fieldValue: string];
}
// type PlanetaryBodyName = keyof FieldNameWithValueMap; // 'Moon' | 'Planet'; 简化示例中未使用
type TupleToObject<T extends [string, any]> = { [key in T[0]]: Extract<T, [key, any]>[1] };
type ObjectModel<T extends keyof FieldNameWithValueMap> = TupleToObject<FieldNameWithValueMap[T]>;
// 鼠标悬停查看这两个示例,类型符合预期;它们需要从导入的类型派生
type MoonObject2 = ObjectModel<'Moon'>; // {visibleStarsCount: BN; hostPlanet: string;}
type PlanetObject2 = ObjectModel<'Planet'>; // {visibleStarsCount: BN; hostStar: string;}
type DRYObjectModelMap = {
    [PlanetaryBodyClass in keyof FieldNameWithValueMap]: ObjectModel<PlanetaryBodyClass>
}
type PickedAttributeSimpler<T extends 'Moon'> = DRYObjectModelMap[T]['visibleStarsCount'];
// 使用下面的定义而非上面的定义时,错误会消失
// type PickedAttributeSimpler<T extends 'Moon'> = DRYObjectModelMap['Moon']['visibleStarsCount'];
function genericFunction<
    T extends 'Moon', // 简化示例中省略了包含 | 'Planet' 的联合类型
    // 省略泛型参数并在下方所有用法中硬编码可以修复错误,
    // 但示例之外的实际函数版本需要保持泛型
>(
    PlanetaryBodyClass: T,
) : PickedAttributeSimpler<T> { // 直接用 DRYObjectModelMap[T]['visibleStarsCount'] 也会报错
    return new BN(42); // 错误 TS(2322): 类型 'BN' 不能赋值给类型 'PickedAttributeSimpler<T>'
}
type ExamplePickedAttribute = PickedAttributeSimpler<'Moon'>; // 类型为 'BN',符合预期
type ExampleGenericPickedAttribute<T extends 'Moon'> = PickedAttributeSimpler<T>; // 类型为 DRYObjectModelMap[T]['visibleStarsCount']
type ExampleGenericInstanceOfPickedAttribute = ExampleGenericPickedAttribute<'Moon'>; // 类型为 BN,符合预期
type HoverToSeeHowTypeShouldResolve<T extends 'Moon'> = DRYObjectModelMap[T]['visibleStarsCount'];
type HoverToSeeHowTypeShouldResolveInstance = HoverToSeeHowTypeShouldResolve<'Moon'>; // 类型为 BN,符合预期

内容的提问来源于stack exchange,提问作者WBT

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 21:18:38