【问题标题】:Typescript: Type inference with union types and ternary operatorTypescript:使用联合类型和三元运算符进行类型推断
【发布时间】:2019-04-16 09:08:44
【问题描述】:

以下打字稿代码编译得很好:

let x: 0 | 1 = 0;

console.log(x);

const r = [true, false];
for (const y of r) {
    if (y || (x !== 1)) {
        x = 1;
    } else {
        x = 0;
    }

    console.log(x);
}

但是,这个语义上等价的代码却没有:

let x: 0 | 1 = 0;

console.log(x);

const r = [true, false];
for (const y of r) {
    x = ((y || (x !== 1)) ? 1 : 0);
    console.log(x);
}

x !== 1 的错误是:

7:17 error TS2367: This condition will always return 'true' since the types '0' and '1' have no overlap.

在这两种情况下,运行编译结果都会产生预期的输出,表明 x 实际上取值 0 1:

0
1
0

我理解错误源于编译器在第二种情况下将0 | 1 类型缩小为0。但是,仅通过查看代码就很清楚 可能 x 被分配了 1(即使没有查看条件)。因此,除非另有明确说明(如第一个示例中那样),否则我希望类型推断采用最通用的类​​型。事实上,在第 1 行我明确告诉编译器我想要更通用的类型:let x: 0 | 1

所以我的问题是,在三元运算符的情况下,类型推断的行为不同是否有合理的原因?

【问题讨论】:

    标签: typescript ternary-operator union-types


    【解决方案1】:

    这个错误其实是因为编译器把x的类型缩小到了0

    我不确定为什么在另一种情况下您没有收到错误 - 因为我希望它在两种情况下都是一致的 - 但我不够聪明,无法编写执行此操作的工具。

    x 的类型被强制为0 | 1 而不是编译器将其缩小为零的示例:

    let x = 0 as 0 | 1;
    
    console.log(x);
    
    const r = [true, false];
    for (const y of r) {
        x = ((y || (x !== 1)) ? 1 : 0);
        console.log(x);
    }
    

    【讨论】:

    • 从输出中可以看出,x 在第一次循环运行后取值为 1。在第二次运行中,条件确实评估为 false(与编译器所说的不同)——这就是 x 设置回 0 的原因。
    • 我认为我不会将错误称为“正确”。它更像是众多tradeoffs in control flow analysis 之一;在这种情况下,在initialization 期间。编译器将x 的类型缩小为0,然后因为将其与1 进行比较而生气......但当然0 | 1 应该与1 相当。缩小范围通常是有帮助的,但在这里不是。可以通过初始化为let x = 0 as 0 | 1 或比较(x !== (1 as 0 | 1)) 来避免。
    • 但是为什么在 CFA 在将 x 的类型确定为 0 | 1 时工作得很好的第一种情况下没有显示这种权衡呢?这对我来说毫无意义
    • @jcalz - 编辑以消除歧义 - 你对“正确”一词的误用是正确的。我还更新了示例,使其更像一个实际的解决方案。
    • 也许我不够清楚:我完全理解为什么会出现错误(将0|1 类型缩小到0)。我的论点是这种行为实际上是不正确的,并且与正常行为不一致:最简单的情况:let x: 0 | 1 = 0; x = 1; 就像一个魅力——编译器正确地抑制了缩小,因为它检测到在程序运行期间 x 实际上可以同时取两个值。一个更复杂的情况是我上面的示例,它也可以正常工作。我想知道这种异常行为是否有合理的原因,因为如果没有,我认为这应该被标记为错误。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-20
    • 2018-07-26
    • 1970-01-01
    • 2021-06-05
    • 2014-08-08
    • 2021-04-15
    • 2019-02-13
    相关资源
    最近更新 更多