【问题标题】:Conditional type not narrowed in false branch条件类型未在错误分支中缩小
【发布时间】: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)

Playground

我(很快)阅读了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


【解决方案1】:

万一将来有人发现:这实际上是一个缺失的功能,据我所知,TypeScript 团队没有计划。

我询问了以下 GitHub 问题:#51040,它被标记为与#48710 重复。就目前而言,这个问题并没有引起太多关注,所以我认为这不会很快发生。但它被标记为“等待更多反馈”,所以如果你有一些,你现在知道该放在哪里了 :)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-22
    • 1970-01-01
    • 1970-01-01
    • 2019-09-09
    • 2018-03-25
    • 2019-08-11
    • 1970-01-01
    相关资源
    最近更新 更多