===
而不是==
,这是众所周知的最佳实践。在TypeScript中,哪种方式更优?是否有一种比另一种更可取?
在我看来,在TypeScript中使用
===
没有意义,因为比较已经仅适用于相等类型,因此你将不会像在纯JavaScript中那样进行(更多或更少好玩的)强制转换。如果暂时放下与JavaScript的兼容性不谈,TypeScript甚至可以去掉===
,不是吗?===
而不是==
,这是众所周知的最佳实践。===
没有意义,因为比较已经仅适用于相等类型,因此你将不会像在纯JavaScript中那样进行(更多或更少好玩的)强制转换。如果暂时放下与JavaScript的兼容性不谈,TypeScript甚至可以去掉===
,不是吗?简短版:
==
运算符会进行意外的类型转换,在 JavaScript 中 1=="1"
是true
。使用 ===
运算符可以避免这种情况。用 ===
进行不同类型的比较总是返回 false
。
TypeScript 编译器将在你使用 ==
进行不同类型比较时发出错误信息。这消除了在 JavaScript 中使用 ==
可能发生的意外类型转换。
这是一个在 TypeScript 编译器中会导致错误信息的 JavaScript 有效用法。所有有效的 JavaScript 也适用于 TypeScript 的观点是一个常见的误解。这只是不正确的。
详细版:
我认为接受的回答是误导性的。Typescript 实际上确实修复了 ==
和 ===
(至少尽可能地修复)。
在 JavaScript 中有两个比较运算符:
==
: 当比较原始值(如数字和字符串)时,此运算符将在执行比较前应用类型转换。 1 == "1"
的结果为 true
。===
: 此运算符不会进行类型转换。如果类型不匹配,它将始终返回 false
。此外,两个运算符都会基于引用来比较引用类型。即使两个独立的对象存储相同的值,它们也永远不被视为相等:
let a = {val:1};
let b = {val:1};
c = a;
a==b; // false
a===b; // false
a==c; //true
a===c; //true
那么在JavaScript比较中,有两种常见的错误来源:
==
比较不同类型的值可能导致意想不到的类型转换。正如现有答案所说,Typescript被设计为Javascript的超集。因此,它不会改变这些比较运算符的行为。如果您在Typescript中编写==
,则会进行类型转换。
那么如何解决这个问题?使用编译器。如果您确实编写了将不兼容的类型与==
进行比较的代码,则会出现编译器错误。尝试编译以下示例:
let str = "1";
let num = 1;
console.log(str == num);
编译器会告诉你:comparisons.ts:4:13 - error TS2367: This condition will always return 'false' since the types 'string' and 'number' have no overlap.
4 console.log(str == num);
~~~~~~~~~~
Found 1 error.
有一个常见的误解,认为任何有效的JavaScript代码也是有效的TypeScript代码。这是不正确的,在上面的代码示例中,TypeScript编译器会抱怨有效的JavaScript代码。
这解决了两个错误源中的第一个:意外的类型转换。但它并未涉及第二个错误源:基于引用的比较。据我所知,当您想要基于对象存储的值进行比较时,您无法使用这些运算符。您将不得不实现自己的equals()
方法。
此外,您可能已经注意到编译器错误是错误的。比较不总是评估为false。我认为这是TypeScript中的一个bug,并已经提出了问题。
假设你从头设计TypeScript,你的首要目标就是优化编写更加安全的代码(TypeScript设计目标1),但有一些限制会阻止你完全实现这个目标。
JavaScript应该可以在不改变任何内容的情况下作为有效的TypeScript代码运行。
CoffeeScript没有关于这方面的保证,因此它可以将所有的==
替换成===
,并告诉用户“不要依赖==
的行为”。TypeScript不能重新定义==
,否则会破坏所有依赖其行为的JavaScript代码(尽管这对第3个目标有悲惨的影响)。
这也意味着TypeScript不能改变===
的功能,例如,在编译时检查两个操作数的类型并拒绝比较不同类型的变量。
此外,兼容性不仅限于JavaScript程序;破坏兼容性也会影响JavaScript程序员,打破他们对==
和===
之间差异的假设。请参见TypeScript非目标7:
引入可能会使用户感到惊讶的行为。而是对其他常用语言采用考虑周全的模式。
所有的TypeScript必须能够表示为JavaScript。此外,尽可能使用惯用的JavaScript语法。
然而,TypeScript编译器完全可以使用返回布尔值的方法来进行所有比较,摒弃==
和===
。这对用户来说甚至更加安全:在每个TypeScript类型上定义一个类型安全的等式方法(有点像C++中的operator==
,只是没有重载)。
因此,有一个解决方法(用于比较类的用户)。在使用类型安全的等式方法之前,unknown
或any
变量可以被缩小其类型。
在您使用JavaScript中===
的地方都要使用它。这样做的好处是避免了==
常见的陷阱,并且不需要维护额外的方法。TypeScript编译器的输出将接近于惯用的JavaScript。使用==
存在与JavaScript非常相似的陷阱,特别是涉及any
、[]
或{}
时。 作为例外,如果库代码不一致,使用== null
来检查null
或undefined
可能会避免一些问题。
一种用于引用相等的方法(类似 === 的行为)可能会与深度/值递归相等性检查混淆。此外,在TypeScript中广泛使用
=== ,使您的代码符合约定通常比任何小的类型安全性更重要。
===
并没有太多的价值。关于“编译到JS”的论点并不真实有效。TS确保两个操作数具有相同的类型。当两个操作数具有相同的类型时,==
和===
表现完全一样。例如:const s : string = "s"
const n : number = 1
console.log(s == n)
TS2367: This condition will always return 'false' since the types 'string'
and 'number' have no overlap
因此,除非你的代码散布着any
或者你会在编译后修改JS,否则仅仅将2eq替换为3eq并不会带来任何好处。
人们只是在寻找保持使用===
的习惯的方法,以理智化。但是,时不时重新考虑自己的原则是一种很好的实践。
从我的个人经验来看,即使在JS中,我也从来没有遇到过==的任何问题。这个“陷阱”被那些从其他语言转到JS的人夸大了,但实际上并不是那么重要。将假阳性换成假阴性或反之并不能使代码自动变得更好。
你最终可以发现像Ryan Florence或Kyle Simpson这样的顶级作者在他们的代码中同时使用==和===-适用于特定情况。所以不要盲目地跟随“最佳实践者”和默认的linter设置。他们错了很多次。
我的观点是应该始终使用===
。
第一条理由:TypeScript不会将==
转换为===
。有些TypeScript翻译器只是剥离类型。因此,如果由于某种原因忘记对程序进行类型检查或者您(或代码的未来维护者)使用类型转换来覆盖类型安全性,则在所有地方使用===
会导致更健壮的代码。虽然不应该发生这种情况,但很多事情都不应该发生。
第二条理由:null == undefined
。这在TypeScript中也是正确的。我认为,如果一个人编写if (x == null)
,它会使代码变得不太可读,因为它暗示了对undefined
的检查,而隐式代码比显式的if (x === null || x === undefined)
不易读。如果这不是故意的,还可能出现微妙的错误。
我认为,在无条件地使用===
时,除了审美偏好之外,没有任何问题。
==
转换为===
,因为TypeScript也有一个类型叫做any
。 - Vasileios Pallas==
“意味着相同的东西”与JavaScript的===
来摆脱===
,从而使==
转译为===
。这不是一项依赖类型检查的提案,同时仍然使用==
的旧含义。 - kshetline(Math.random() < 0.5 ? 3 : "3") == 3;
,则生成的 JS 在运行时必须始终评估为true
。 - jcalz