简体   繁体   English

Typescript:检查变量的真实性不会对未定义进行类型防护吗?

[英]Typescript: checking truthiness of variable doesn't type-guard against undefined?

class Base {}

function log(arg: number) {
    console.log(arg);
}

function fn<T extends typeof Base>(
    instance: Partial<InstanceType<T>>,
    key: keyof InstanceType<T>,
) {
    const val = instance[key];
    if (val) {
        log(val);
    }
}

TS Playground: https://www.typescriptlang.org/play?#code/MYGwhgzhAEBCkFNoG8C+AodAzArgO2ABcBLAez2hFIHMAKMAJ2oC5o8cBbAIwQYEoU6aMOjByEUiAQA6KnUbU+AbnQZs+ImQpY8AHgAq0BAA9CCPABMYhAJ4AHBKSxxEAPlpCRxPBEJgCCKwACowkYCC6AJI+fgH69ggGrq4ANJ7CANYINqxZNk7Q0b7+wAjxDklpAsjpouKE0ABu4dAAvNDexQEA2nkAuioiHc60zSDVtUNyo+HKtRgYQA TS Playground: https://www.typescriptlang.org/play?#code/MYGwhgzhAEBCkFNoG8C+AodAzArgO2ABcBLAez2hFIHMAKMAJ2oC5o8cBbAIwQYEoU6aMOjByEUiAQA6KnUbU+AbnQZs+ImQpY8AHgAq0BAA9CCPABMYhAJ4AHBKSxxEAPlpCRxPBEJgCCKwACowkYCC6AJI+fgH69ggGrq4ANJ7CANYINqxZNk7Q0b7+wAjxDklpAsjpouKE0ABu4dAAvNDexQEA2nkAuioiHc60zSDVtUNyo+HKtRgYQA

I get:我得到:

Argument of type 'InstanceType<T>[keyof InstanceType<T>] | undefined' is not assignable to parameter of type 'number'.
  Type 'undefined' is not assignable to type 'number'.

Shouldn't if (val) guard against undefined ? if (val)不应该防范undefined吗? It works if I change it to log(val?? 0) .如果我将其更改为log(val?? 0)它将起作用。

Also, I'm surprised log(val?? 0) works.另外,我很惊讶log(val?? 0)有效。 val could be a truthy value that's not a number, but log() expects a number. val可能是一个不是数字的真实值,但log()需要一个数字。 Why doesn't this throw an error?为什么这不会引发错误?

The problem is well known .这个问题是众所周知的。 You may get some insight what's really happening inside the type checker from this comment :您可能会从此评论中了解类型检查器内部真正发生的事情:

The core problem is that the narrowed type of fooAnchor is not really speakable.核心问题是 fooAnchor 的窄化类型并不能真正说出来。 Its unnarrowed type is Partial<FooAnchorMap>[keyof TMap], which isn't a union that we can remove undefined and null from to produce some other type that would be provably-assignable to HTMLElement.它的未缩小类型是 Partial<FooAnchorMap>[keyof TMap],它不是一个联合,我们可以从中删除 undefined 和 null 以生成可证明可分配给 HTMLElement 的其他类型。

There is work in progress to resolve it.工作正在进行中来解决它。 But as of now you're left only with workarounds.但是到目前为止,您只剩下解决方法了。

function fn<T extends typeof Base>(
    instance: Partial<InstanceType<T>>,
    key: keyof InstanceType<T>,
) {
    const val: InstanceType<T>[keyof InstanceType<T>] | undefined = instance[key];
    if (val) {
        log(val);
    }
}

playground link游乐场链接

And you'll get the correct error: Type 'InstanceType<T>[string]' is not assignable to type 'number'.你会得到正确的错误: Type 'InstanceType<T>[string]' is not assignable to type 'number'.

The undefined bit is a red herring; undefined的位是红鲱鱼; this is only being flagged because strictNullChecks is enabled which means unless you declare这只是被标记,因为strictNullChecks已启用,这意味着除非您声明

function log(arg: number) {
    console.log(arg);
}

as作为

function log(arg: number | undefined) {
    console.log(arg);
}

it is going to complain whenever you pass anything in which may resolve to undefined .每当您传递任何可能解析为undefined的内容时,它都会抱怨。 Disabling strictNullChecks will eliminate that error (though present others with the above code);禁用strictNullChecks将消除该错误(尽管向其他人提供上述代码); alternatively guaranteeing that undefined is handled before being passed in (eg ?? 0 ) will also work.或者保证在传入之前处理undefined (例如?? 0 )也可以。

Also, I'm surprised log(val?? 0) works.另外,我很惊讶 log(val?? 0) 有效。 val could be a truthy value that's not a number, but log() expects a number. val 可能是一个不是数字的真实值,但 log() 需要一个数字。 Why doesn't this throw an error?为什么这不会引发错误?

This should error if val?? 0如果val?? 0 val?? 0 doesn't resolve to a number and log() expects a number, ie in the scenario you described where a truthy non-number is passed in. This fails correctly for me in the playground, do you have an example of this not working? val?? 0不能解析为数字并且log()需要一个数字,即在您描述的场景中传入了一个真实的非数字。这对我来说在操场上失败了,你有一个不工作的例子?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM