假设您有一个抛出特定配置错误的函数:
function throwMyError(): never {
throw new Error("My Custom error")
}
并且您有一个可为空的值:
declare const str: string | null
您可以将该值缩小为不可为空的值,如下所示:
if(!str) throwMyError()
str.toLocaleLowerCase() // fine
现在将该函数调用放入对象文字中,它不能再进行相同的缩小:
const foo = { throwMyError }
if (!str) foo.throwMyError()
str.toLocaleLowerCase() // 'obj' is possibly 'null'.(18047)
或者:
const bar = {
throwMyError: (): never => {
throw new Error()
}
}
if (!str) bar.throwMyError()
str.toLocaleLowerCase() // 'obj' is possibly 'null'.(18047)
当从对象类型调用抛出函数时,为什么缩小不起作用?
可以在不创建类型谓词函数的情况下解决这个问题吗?
相关问题:类型缩小和从不起作用
但这似乎并没有解决这个问题,因为在所有情况下函数类型都被显式注释为返回never
返回
never
函数被视为影响控制流分析的断言的条件在实现 PR microsoft/TypeScript#32695中详细说明。它看起来像这样:您遇到的问题
foo
是,bar
它们都是没有显式类型注释的变量。您已经允许编译器推断它们的类型,这在几乎所有其他情况下都是完全合理的事情。never
但显然,对于断言函数和返回函数来说,支持这一点太难了;据说这会导致类型检查器速度减慢和循环警告。如果你想要
foo
并且bar
工作,那么你将需要显式地注释它们,如下所示:或者
这就是您想要的行为,对于此处的示例代码来说,不需要太多额外的工作。但实际上,这种对类型注释的限制使得使用
never
返回和断言方法成为一个重大负担,因为您发现自己需要为类型提供显式名称,否则这些名称可以方便地匿名并为您推断。根据使用情况,这可能是轻微的烦恼 (const foo: Foo = ⋯
) 到彻底破坏交易 (const baz: Baz<Map<string, boolean>, "qux", [number, "hello"], Baz<Map<string, Date>, "quux", [boolean, "goodbye"], ⋯>> = ⋯
)。因此请谨慎行事。Playground 代码链接