Javascript 我们应该使用!或(可选链接)在typescript中?

Javascript 我们应该使用!或(可选链接)在typescript中?,javascript,reactjs,typescript,Javascript,Reactjs,Typescript,我只是用React练习打字。当我谈到这段代码时,我发现要么和?。(可选链接)可以使用 从“react”导入{FC,FormEvent,useRef}; 常数NewTodo:FC=()=>{ const textInputRef=useRef(null); 函数ToDosBMitandler(ev:FormEvent){ ev.preventDefault(); //这里 const enteredText=textInputRef.current!?.value; console.log(输入文

我只是用React练习打字。当我谈到这段代码时,我发现要么
?。
(可选链接)可以使用

从“react”导入{FC,FormEvent,useRef};
常数NewTodo:FC=()=>{
const textInputRef=useRef(null);
函数ToDosBMitandler(ev:FormEvent){
ev.preventDefault();
//这里
const enteredText=textInputRef.current!?.value;
console.log(输入文本);
}
返回(
待办事项文本
添加待办事项
);
};
导出默认NewTodo;

我对
的了解
是告诉Typescript,它从来没有
null
未定义的值。和
?。
可选链接是为了防止在未找到属性时出错,并返回
未定义的
。在上述情况下,我可以使用
?。
或甚至两者的组合
,并且类型脚本编译器不抗议。那么,使用哪一种是最好和最安全的呢?

这是完全不同的事情

空断言运算符
是您,程序员,向编译器断言您知道的一个事实,即由于编译器无法证明的原因,属性访问不能失败。对于运行时错误,它并不比程序员对编译器所做的任何其他断言更安全,因为您更清楚它所做的

const foo = null;
foo!.someProperty; // compiles but you will get a TypeError! Cannot read property 'someProperty' of null or undefined.
另一个是可选的链接操作符。它基本上是这种常见Javascript模式的简写:

const something = foo && foo.bar && foo.bar.baz;
但这比简单的速记要好,因为如果其中一个值是错误的,但一些错误的值支持属性访问,则上述操作将失败。使用空合并,您只需编写:

const something = foo?.bar?.baz;
你完成了。就像Javascript版本一样,它是“安全的”,因为它保证在尝试访问空引用的属性时不会导致运行时错误

在您所处的特定情况下,您可能需要以下内容:

const enteredText = textInputRef.current?.value || '';

很明显,不管发生什么,结果都是一个字符串。

这是完全不同的事情

空断言运算符
是您,程序员,向编译器断言您知道的一个事实,即由于编译器无法证明的原因,属性访问不能失败。对于运行时错误,它并不比程序员对编译器所做的任何其他断言更安全,因为您更清楚它所做的

const foo = null;
foo!.someProperty; // compiles but you will get a TypeError! Cannot read property 'someProperty' of null or undefined.
另一个是可选的链接操作符。它基本上是这种常见Javascript模式的简写:

const something = foo && foo.bar && foo.bar.baz;
但这比简单的速记要好,因为如果其中一个值是错误的,但一些错误的值支持属性访问,则上述操作将失败。使用空合并,您只需编写:

const something = foo?.bar?.baz;
你完成了。就像Javascript版本一样,它是“安全的”,因为它保证在尝试访问空引用的属性时不会导致运行时错误

在您所处的特定情况下,您可能需要以下内容:

const enteredText = textInputRef.current?.value || '';
无论发生什么,结果都是一个字符串,这一点非常清楚。

比其他方法更安全

考虑以下接口:

interface Foo {
    bar?: {
        baz: string;
    }
}
属性是可选的。如果它不存在,当您阅读它时,它将是未定义的。如果它确实存在,它将具有类型为
string
baz
属性。如果您只是尝试访问
baz
属性,而不确保定义了
bar
,您将收到一个编译器错误,警告您可能存在运行时错误:


可选链接在运行时具有实际效果,如果您尝试访问的属性不存在,则会短路到
未定义的
值。如果您不确定某个属性是否存在,则可选链接可以保护您免受某些运行时错误的影响。TypeScript编译器不会抱怨以下代码,因为它知道您现在所做的是安全的:

function optChain(foo: Foo) {
    console.log(foo.bar?.baz.toUpperCase());
}

optChain({ bar: { baz: "hello" } }); // HELLO
optChain({}); // undefined
如果不确定属性访问是否安全,并且希望运行时检查保护您,则应使用可选链接


另一方面,非空断言在运行时没有任何效果。这是一种告诉编译器,即使它无法验证某个属性是否存在,您也在断言这样做是安全的方法。这也有阻止编译器抱怨的效果,但是您现在已经接管了确保类型安全的工作。如果在运行时,您声明为定义的值实际上未定义,则您向编译器撒谎,可能会遇到运行时错误:

函数nonNullAssert(foo:foo){
console.log(foo.bar!.baz.toUpperCase());
}
非空断言({bar:{baz:{hello}});//你好
非空断言({});// 使用起来比使用起来更安全

考虑以下接口:

interface Foo {
    bar?: {
        baz: string;
    }
}
属性是可选的。如果它不存在,当您阅读它时,它将是未定义的。如果它确实存在,它将具有类型为
string
baz
属性。如果您只是尝试访问
baz
属性,而不确保定义了
bar
,您将收到一个编译器错误,警告您可能存在运行时错误:


可选链接在运行时具有实际效果,如果您尝试访问的属性不存在,则会短路到
未定义的
值。如果您不确定某个属性是否存在,则可选链接可以保护您免受某些运行时错误的影响。TypeScript编译器不会抱怨以下代码,因为它知道您现在所做的是安全的:

function optChain(foo: Foo) {
    console.log(foo.bar?.baz.toUpperCase());
}

optChain({ bar: { baz: "hello" } }); // HELLO
optChain({}); // undefined
如果不确定属性访问是否安全,并且希望运行时检查保护您,则应使用可选链接


另一方面,非空断言在运行时没有任何效果。这是你告诉编译器