TypeScript泛型函数返回类型匹配报错原因咨询
TypeScript泛型返回类型不匹配报错原因解析
示例代码
class ModelA { static A: number; } class ModelB { static B: number; } const allModels = { modelA: () => ModelA, modelB: () => ModelB, } as const; type ModelTypes = typeof allModels; type ModelKeys = keyof ModelTypes; export function modelLookup<T extends ModelKeys>(modelName: T): ReturnType<ModelTypes[T]>{ const modelGetter= allModels[modelName]; const PerfectlyInferredTypeUnion = modelGetter(); // typeof ModelA | typeof ModelB let ThisShouldAllowAnyModel: ReturnType<ModelTypes[ModelKeys]> = ModelA; // Fine. ThisShouldAllowAnyModel = ModelB; // Fine. let ThisShouldAllowAnyModelToo: ReturnType<ModelTypes[T]> = ModelA; // Not fine. But T can be only 'modelA' or 'modelB', so resulting type should be `typeof ModelA | typeof ModelB`; return PerfectlyInferredTypeUnion; } const ShouldBeModelA = modelLookup('modelA'); ShouldBeModelA.A // This is working tho
问题现象
外部调用modelLookup('modelA')时返回类型正确,但函数内部return modelGetter()时报错:
Type 'typeof ModelA | typeof ModelB' is not assignable to type 'ReturnType<{ modelA: () => typeof ModelA; modelB: () => typeof ModelB; }[T]>'. Type 'typeof ModelA' is not assignable to type 'ReturnType<{ modelA: () => typeof ModelA; modelB: () => typeof ModelB; }[T]>'.
报错原因
核心是TypeScript的泛型类型检查逻辑和你的理解存在差异:
- 当你定义泛型参数
T extends ModelKeys时,T代表的是单个具体的键类型(比如调用时的'modelA'或'modelB'),而非ModelKeys对应的联合类型。因此函数的返回类型ReturnType<ModelTypes[T]>是单个具体的类构造函数类型(typeof ModelA或typeof ModelB),而非两者的联合。 - TypeScript对联合类型的赋值采用逐分支验证:它会尝试把
modelGetter()返回的联合类型(typeof ModelA | typeof ModelB)中的每个成员,分别匹配到泛型返回类型上。但因为T是不确定的单个类型——如果T是'modelA',那typeof ModelB就不匹配;如果T是'modelB',typeof ModelA也不匹配,所以整个联合类型无法通过类型检查。 - 你误以为
ReturnType<ModelTypes[T]>会是联合类型,这是混淆了泛型参数的约束范围和泛型参数的实际类型:约束T extends ModelKeys只是限定了T的可选范围,但T本身始终是单个具体值对应的类型,只有当直接使用ModelKeys作为类型参数时,才会得到联合类型(也就是代码中ThisShouldAllowAnyModel的情况)。
内容的提问来源于stack exchange,提问作者Istvan Tabanyi
相关产品推荐
相关产品推荐

