打字稿是否总是假设不允许副作用?

Does typescript always assumes side effects are not allowed?

提问人:cglacet 提问时间:9/18/2023 更新时间:9/18/2023 访问量:60

问:

我有以下玩具示例,其中打字稿警告我错误:

type obj = {
    ok: "ok" | "error",
}

function main(a: obj){
    a.ok = "ok";
    reloadFromDatabase(a);
    if (a.ok == "error"){ // TS error 
        console.log("Error");
    }
}

// Any function that has side effects on object a.
// For example, typeorm's `a.reload()`
function reloadFromDatabase(a: obj){
    a.ok = "error";
}

错误是:

This comparison appears to be unintentional because the types '"ok"' and '"error"' have no overlap.(2367)

如果您假设不允许突变对象的副作用,这是有道理的,但 的类型是 所以它应该允许 的两个值 () 。aobj"ok" | "error"obj.isOk

在这个特定的代码示例中,我掌握了具有副作用的函数,因为它很好,因为我可以返回突变的对象:

function main(a: obj){
    a.ok = "ok";
    a = reloadFromDatabase(a);
    if (a.ok == "error"){ // This time its fine
        console.log("Error");
    }
}

function reloadFromDatabase(a: obj){
    a.ok = "error";
    return a;
}

但是在我的用例中,我无法访问它,它什么也没返回(它只是改变了对象)。reloadFromDatabase

这是打字稿选项吗?这似乎是一个合法的错误吗?我是否错过了允许突变会完全破坏打字稿逻辑(提供较少/没有类型安全性)的情况?

打字稿 突变 副作用

评论


答:

2赞 Matthieu Riegler 9/18/2023 #1

这是在控制流分析中做出的权衡的一部分:

你可以看看这个著名的问题:https://github.com/microsoft/TypeScript/issues/9998

可以总结为以下问题:

主要问题是:当一个函数被调用时,我们应该做什么 假设它的副作用是?

现在,TS假设没有副作用。

解决方法是使用类型断言:

if (a.ok as obj['ok'] == "error") { // ok asserted as 'ok'|'error'
   console.log("Error");
}

评论

1赞 Jared Smith 9/18/2023
不是 DV,但这个答案绕过了仅链接的界限,尤其是在您添加变通方法代码块之前。也许在答案的文本中添加一些链接的 github 线程的嘶嘶声?
1赞 Matthieu Riegler 9/18/2023
你是对的,答案应该更好一点
0赞 cglacet 9/19/2023
总结这个巨大的线索对我来说确实很重要。解决方法确实解决了我的问题
0赞 cglacet 9/19/2023
也许有一个例子会很有趣,说明如果不做出这个假设会有什么突破(感受一下这里所做的妥协)?