TypeScript "Mapped Types"分布的结果已发生变化,

7dl7o3gd  于 6个月前  发布在  TypeScript
关注(0)|答案(6)|浏览(43)

Bug报告

在4.3.2或更高版本的typescript中,'Mapped Types'的转换结果发生了变化。

💻 代码

type Base = { 100: { a: number }; 200: { b: string } }
type NewType<T = Base> = {
  [P in keyof T ]: {
    code: P
    body: T[P]
  }
} extends {
  [P in any]: infer R
}
  ? R
  : never

let test: NewType

🙁 实际行为

  • 4.3.0-beta及更早版本
let test: {
    code: 100;
    body: {
        a: number;
    };
} | {
    code: 200;
    body: {
        b: string;
    };
}
  • 4.3.2
let test: {
    code: keyof Base;
    body: {
        a: number;
    } | {
        b: string;
    };
}

🙂 预期行为

希望恢复到4.3.0-beta之前的操作!

5n0oy7gb

5n0oy7gb2#

我能够通过插入一次'extends'来暂时解决这个问题!
这段代码在4.3.2及之前的版本中也有效。

qvtsj1bj

qvtsj1bj3#

另一个解决方法(在ts 4.4.0-dev.20210530上尝试过):

type NewType<T> = {
  [P in keyof T]: {
    code: P
    body: T[P]
  }
}[keyof T]

type Base = { 100: { a: number }; 200: { b: string } }
declare const test: NewType<Base>
de90aj5v

de90aj5v4#

看起来这是被 #43649 破坏的。

yebdmbv4

yebdmbv45#

@weswigham 我不确定 #43649 的变化。他们在这个问题中破坏了示例,因为当我们检查 R 的推断是否可以分配给 R 的约束(由 #43649 计算)时,该约束包含对 T 的未示例化的引用,因此分配性检查失败。然后选择约束,随后使用传递给 T 的类型示例化它。但那时已经太晚了,不是我们想要的结果。我们可能可以考虑在分配性检查之前添加一些逻辑来示例化约束,但这将进一步复杂化条件类型的推理过程,我甚至不确定我是否同意这是正确的做法。我认为对于推断出的 R 没有约束是完全可以的——老实说,在许多类似的情况中,我们确实不会产生约束(例如,如果检查类型只是一个普通的对象类型)。
我的建议是撤销 #43649。当然,这意味着 #43357,它修复的问题需要其他解决方案。正如你自己指出的那样,它从来就不应该起作用,我认为正确的解决方案是在 KeysWithoutStringIndex<T> 类型中显式与 keyof T 相交,即

type KeysWithoutStringIndex<T> =
    ({ [K in keyof T]: string extends K ? never : K } extends { [_ in keyof T]: infer U } ? U : never) & keyof T;
k10s72fa

k10s72fa6#

我认为我们的句法推断约束规则一开始是非常任意的(我们匹配哪些类型参数以及在哪些位置,这基本上是根据请求选择的)-我通过添加一个来"修复"这个问题,因为技术上说这种行为的变化实际上是一个回归,而添加这些句法约束是相对自由的。额外的示例化可能是我们能做的最好的事情,以保持旧的行为。我们可以撤销它...但是然后我们会重新引入旧的回归...

相关问题