TypeScript 在一种情况下的类型缩小不会传播到下一个情况,

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

🔎 搜索词

  • 类型缩小
  • 开关语句

🕗 版本与回归信息

  • 这是我尝试的每个版本的行为,我查阅了关于开关语句和类型缩小的常见问题解答。

⏯ Playground链接

https://www.typescriptlang.org/play?ts=5.3.0-beta#code/GYVwdgxgLglg9mABMOcAUBDATgcwFyIDOUWMYOiAPouACYCmwZ9tAlIgN4BQivRA7jCgQAFojQkQ9dtz5zEEDIXqJsFALyaaYBkzAs8Pecagiscfon2WAolnNY0rANxcjxxctW4AdMWxQhADqQiJoAEQAHuGsBAD0cYj09nBYiAAqAMoAjAAcAAwALLkEAORqpYgwhIgADnCEhDAARgA2AJ6IpXSMzLSlPu7GfFj0UCBYSOEAguGuQ3K6GCCtUIbD8qPjk4jhAEJzQwC+XCdAA

💻 代码

function foo(arg: string | undefined) {
    switch (true) {
        case arg === undefined:
            throw new Error();

        case arg.startsWith("x"): // error TS18048: 'arg' is possibly 'undefined'.
            return "A";

        default:
            return "B";
    }
}

🙁 实际行为

在第二个情况中为 error TS18048: 'arg' is possibly 'undefined'.

🙂 预期行为

我希望在第二个情况语句中,类型被缩小为字符串。

关于问题的附加信息

另请参阅 #56352 。@Andarist 请回复。

uklbhaso

uklbhaso1#

如果这听起来有些奇怪,请原谅我,但你真的会写这样的代码吗?

wrrgggsh

wrrgggsh2#

如果这听起来很奇怪,请原谅我,但你真的会写这样的代码吗?
不会。我只是想把这个例子简化到仍然能复现相同行为的程度。原始代码要更合理一些。:-)

0h4hbjxa

0h4hbjxa3#

话虽如此,你们在5.3版本的发布说明中提出了switch (true)模式。😄
在我们能在Javascript中实现模式匹配(这仅仅是TC39的第一阶段)之前,我想这是一个合理的替代方案。

qvsjd97n

qvsjd97n4#

"suggesting"是一个强烈的术语😄
MDN最好的例子中有一些项目使用它来代替模式匹配。
无论如何,这些问题至少暴露出我们的CFA实际上并不在case表达式之间流动,这在之前是真实的。

6za6bjd0

6za6bjd05#

我遇到了一个类似的问题,与这个代码练习有关:

const reA = /^A(\d+)$/;
const reB = /^(\d+)B$/;

function f(line: string): number {
    let m: RegExpExecArray | null | undefined;
    switch (true) {
        case !!(m = reA.exec(line)): {
            return m![1].length;
        }
        case !!(m = reB.exec(line)): {
            return m![1].length;
        }
    }
    return -1;
}

这段代码在 TypeScript 5.2 中可以正常工作。
升级到 TypeScript 5.3 后,编译器报错 "Property 'length' does not exist on type 'never'.",因为它错误地认为第二个情况中的 mnever
如果我在第二个情况下声明一个相同类型的单独变量 m2 并将其赋值给该变量,代码就可以正常工作。
如果这听起来很奇怪,那么你实际上会这样写代码吗?
实际上,我是这么写的,这是真正的代码。
switch (true) 是 Go 编程语言中的一种常见模式,我将它引入了 TypeScript。

dgiusagp

dgiusagp6#

我认为这与直接相关性不大,但新实现中出现了一个新的bug,可能值得单独开一个issue。

x3naxklr

x3naxklr7#

我认为这个问题表现得更不那么奇特:意外的重复案例常量。

function f(x: "a" | "b"){
    switch (x) {
        case "a": break;
        case "a": break;  // no error ☹️
        case "b": break;
    }
}

如果在switch cases之后缩小操作正确,那么在第一个分支之后,x 的类型将缩小为 "b" ,第二个分支将是一个类型错误。
为了比较,等效的else-if链行为如下:

if (x === "a") {
    ...
} else if (x === "a") {  // error 🙂
    ...
} else if (x === "b") {
    ...
}

相关问题