为什么这会给出打字稿警告? [英] Why does this give a Typescript warning?

查看:79
本文介绍了为什么这会给出打字稿警告?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么在此.tsx组件中对 needsString(var1)的第二次调用给出警告,但没有给出第一或第三次调用?而且,如果我更改代码以使用 var2 而不是 var1 (我认为它们具有完全相同的类型),则不会收到警告.有什么作用?

Why does the second call to needsString(var1) in this .tsx component give a warning, but not the first or third calls? And if I change the code to use var2 instead of var1 (which I think have exactly the same types), I don't get a warning. What gives?

import { useParams } from "react-router-dom";

const DeleteTeams2 = ({ var2 } : { var2: string | undefined})=> {
    // use var here so that var1 and var2 get exactly the same types
    var { var1 } = useParams();

    function needsString(str : string) : string {
        return "hello";
    }

    // I can tell typescript that var1
    // definitely is non-null with an if statement
    if (! var1)
        throw new Error("bad, bad varN");

    // This call is warning-free
    needsString(var1);

    // But JSX doesn't know that var1 is non-null for some reason...
    return (
        <div
            onClick={() => {
                // I get a warning from this!
                needsString(var1);
            }}
        >
            { needsString(var1) }
        </div>
    )
}

当我将鼠标移到 var1 var2 的定义上时,它们似乎都具有相同的类型: var varN:string |未定义.

When I move the mouse over the definitions of both var1 and var2, they both seem to have the same type: var varN: string | undefined.

由于if语句,我希望 var1 在if语句之后表现为 string .实际上,它适用于 var2 ,但不适用于 var1 .

Due to the if statement, I expect var1 to behave as a string after the if statement. And indeed it does for var2, but not for var1.

但是从第一次调用 needsString(var1)时我得到一个警告:

But I get a warning from the first call to needsString(var1):

TypeScript error in /path/to/foobar.tsx(146,29):
Argument of type 'string | undefined' is not assignable to parameter of type 'string'.
  Type 'undefined' is not assignable to type 'string'.  TS2345

    144 |             onClick={() => {
    145 |                 // I get a warning from this!
  > 146 |                 needsString(var1);
        |                             ^
    147 |             }}
    148 |         >
    149 |             { needsString(var1) }

删除了对非null断言运算符,因为一些评论指出,我没有使用非null断言运算符.

Removed reference to Non-null assertion operator as I was not using a Non-null assertion operator as several comments have pointed out.

推荐答案

问题在于此处的代码:

onClick={() => {
  // I get a warning from this!
  needsString(var1);
}}

不会与此代码同时执行:

will not be executed at the same time as this code:

if (! var1)
  throw new Error("bad, bad varN");

// This call is warning-free
needsString(var1);

此外, var1 是可变的引用,因此从TypeScript的角度来看,可能在您实际使用它时检查其是否为空之间进行了更改.例如,请考虑以下示例代码:

Moreover, var1 is a mutable reference, so from TypeScript's perspective it might change between checking if it's empty you actually using it. For example consider this sample code:

//it's populated
var myVar = "hello";

//verify it's populated
if(!myVar) throw Error("WRONG!");

//absolutely positively `myVar` is populated

//set this to execute later
setTimeout(() => console.log("myVar", myVar));

//change it
myVar = undefined;

因此,TypeScript只能确定重新分配 var1 . useParams()函数返回键入为

So, TypeScript can only determine that var1 might be reassigned. The useParams() function returns an object typed as

{ [K in keyof Params]?: string | undefined; }

这意味着 var1 的可能类型只是 string |未定义.如果值更改(TypeScript无法确定是否更改),则可以看到不允许使用 undefined .

which means that the possible type for var1 is just string | undefined. If the value changes (TypeScript has no way to determine if it does or not), then it can see that undefined is not allowed.

可以简单声明为<代码>常量{VAR1} (游乐场链接),这使得它的类型<代码>串仅作为它保证了编译器,你不会在声明和用法之间更改它.

You can simple declare it as const { var1 } (Playground Link) which makes its type string only as it assures the compiler you'd not change it between declaration and usage.

或者,将类型显式设置为仅 string : var {var1} = useParams()as {var1:string}; 游乐场链接.编译器会接受也许您已经对其进行了重新分配,但它至少知道将变量更改为唯一可能的是另一个字符串.满足以后使用的类型,因此可以工作.但是,这需要类型断言,并且一如既往,这取决于您是 sure ,否则,您可能会遇到TypeScript编译器看不到的运行时错误(因为您已经故意将其蒙蔽")

Alternatively, explicitly set the type to only string: var { var1 } = useParams() as { var1: string }; Playground Link. The compiler would accept that maybe you've reassigned it but it would at least know that the only possible thing you would change the variable to is another string. Which satisfies the type used later and would thus work. However, that requires a type assertion and as always, it relies on you being sure this would be the case, otherwise you might get a runtime error that the TypeScript compiler cannot see (because you've "blinded" it, intentionally)

如果出于某种原因(将其更改或其他任何原因)将 var1 设置为常量感到不安,则只需对 var1 进行常规检查,然后设置一个新的常量:

If you feel uneasy setting var1 to a constant for whatever reason - either you change it or anything else, then you can just do your normal check for var1 and then set a new constant:

if (! var1)
  throw new Error("bad, bad varN");

const checkedVar1 = var1;

/* ... */

onClick={() => {
  // I get a warning from this!
  needsString(checkedVar1);
}}

游乐场链接

这仍然可以正常工作,并且可以满足TypeScript编译器的要求,即在为代码分配一个肯定是字符串的字符串与实际分配的字符串之间,不会更改 checkedVar1 (我想将其命名为更明智的名称)使用.

This still works and will satisfy the TypeScript compiler that checkedVar1 (I assume you'd name it something more sensible) is not changed between definitely being being assigned something that's definitely a string and when it's actually used.

这篇关于为什么这会给出打字稿警告?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆