【发布时间】:2022-10-04 18:33:45
【问题描述】:
假设我需要一个类型来获取Obj 的某个属性的值。唯一的问题是,生活中经常会遇到特殊情况。所以我有以下代码:
interface Obj {
foo: number;
}
// Ignore the actual type of special case, it's only for
// demonstrative purposes.
type SpecialCase = { id: number };
type ObjKey = keyof Obj | "specialCase";
// This is the desired type I need:
type ObjVal<Key extends ObjKey> = Key extends "foo" ? Obj[Key] : SpecialCase;
这很好用。编译器使用Key extends "foo" 告诉"foo" 是Obj 的实际属性,并让我对其进行索引。但可悲的是,Obj 有更多的键,只有"foo"。因此,显而易见的下一步行动是扭转这种情况。但由于某种原因,TypeScript 无法缩小表达式的错误分支:
interface Obj {
foo1: number;
foo2?: number;
bar1: string;
bar2?: string;
}
type SpecialCase = { id: number };
type ObjKey = keyof Obj | "specialCase";
type ObjVal<Key extends ObjKey> = Key extends "specialCase" ? SpecialCase : Obj[Key];
// Error: Type 'Key' cannot be used to index type 'Obj'.(2536)
我(很快)阅读了the chapter about conditional types,但没有找到任何有用的信息。
这种行为对我来说似乎很奇怪。我能想到 TypeScript 会这样做的唯一原因是,Key 是否“更多”而不仅仅是ObjKey。但据我所知,对泛型Key extends ObjKey 的约束只允许ObjKey 的变体。
我在网上搜索了一下,但我似乎缺乏足够的搜索词,并且找不到它。指点非常感谢!
【问题讨论】:
-
@Elias - 对我来说,这不是一种解决方法,这就是我写它的方式。但我真的很想知道为什么你的版本不起作用。 :-)
-
@Elias - 你似乎得到了我不同意的印象。我没有,我也希望它能够工作,但我已经被
extends咬到足以怀疑边缘情况。 :-) 不,我不知道这方面存在的问题(但我对 TypeScript 问题很敏感)。我怀疑来自乌克兰的 jcalz 或船长-yossarian 或 Titian Cernicova-Dragomir 会在适当的时候解释它。 -
@Elias 对于运行时值而不是类型范围,您是正确的 CFA。这正是我想说的,我们不应该期望 CFA 在条件类型中。我认为因为
subtyping是一个复杂的话题,TS 甚至不要试图推断false分支并且-期望您提供另一种类型的条件语句 -
@T.J.Crowder 这些只是我的想法(逆向工程),我没有找到合适的问题。
-
@captain-yossarianfromUkraine
This is exactly I wanted to say, that we should not expect CFA inside conditional types. I think because subtyping is a complex topic- 我确信这是一个复杂的话题,但正如你所看到的,至少我确实做到了预计这工作。此外,我认为这是一个(有些重要)特征。 JavaScript 是一种非常动态的语言,不幸的是它需要像 TypeScript 这样的工具来拥有非常动态和健壮的类型系统。你认为值得为此打开一个 GitHub 问题吗?并感谢您的努力!
标签: typescript