TypeScript:类型缩小:断言不是未定义的,因此从类型中排除

TypeScript: type narrowing: assert not undefined and hence exclude from type

这两行都在 _e[k] 上抱怨错误 "Object possibly undefined":

obj[k] = typeof _e[k] === "undefined" ? "" : _e[k].toString();
obj[k] = _e[k] === undefined ? "" : _e[k].toString();

_e[k] 是多种类型的联合,因此手动类型转换不适用。如何消除错误?

更新: 因此,以更一般的方式,我的问题可以表述为:是否有一种方法可以通过检查应排除的特定类型来缩小变量的类型?

最小示例:

class test {
    a!: string;
    b?: number;
}
const t: test = { a: "hi", b: 2 };
for (const k of Object.keys(t) as Array<keyof test>) {
    console.log(t[k] == undefined ? "LOL" : t[k].toString());
}

因此,适用于我的用例(但不适用于许多其他情况)的(相当老套的)解决方法是:

obj[k] = _e[k] === undefined ? "" : String(_e[k]);

仍然对适用于更一般情况的(更好的)建议感兴趣(参见问题更新)

长期以来 bug/issue TypeScript 不执行 control flow analysis to narrow the type of a property if the property key is a variable: microsoft/TypeScript#10530;它没有得到解决,因为修复造成了很大的性能损失。在您的情况下,这意味着 _e[k] 上的类型保护检查不会影响 _e[k].

的后续使用

我推荐的解决方法是将索引访问的 属性 分配给一个新变量并检查它:

const ek = _e[k]; // new variable
obj[k] = typeof ek === "undefined" ? "" : ek.toString(); // no error now

新变量 ek 应用了正常的控制流类型分析,并且您的类型保护起作用了。

不同用例的其他可能性:

  • 如果您已经针对 undefinednull 进行了检查,但编译器无法计算出来,最简单的更改是使用 non-null assertion operator ! :

    obj[k] = typeof _e[k] === "undefined" ? "" : _e[k]!.toString(); // non-null assertion
    
  • 您可以将您的类型排除代码重构到它自己的独立表达式中,这样您就不必重新检查原始值。例如:

    obj[k] = (_e[k] || "").toString(); // refactor
    

    该特定代码仅适用于唯一的 falsy_e[k] 可以有 undefined""。如果 _e[k] 可以是 0 那么那将给出不同的结果。一般来说,你可以创建一个新函数来做任何你想做的事情:

    function defined<T, U>(x: T | undefined, dflt: U): T | U {
        return typeof x !== "undefined" ? x : dflt;
    }
    obj[k] = defined(_e[k], "").toString(); // refactor 2
    

好的,希望其中之一对您有所帮助;祝你好运!

Playground link to code