“await” 只能和 promises一起使用
可以await
在非Promise
的值上使用,但它是无用的且具有误导性。await是暂停执行,直到Promise的异步代码运行完毕。
不兼容的代码示例:
let x = 42;
await x; // Noncompliant
合规解决方案:
let x = new Promise(resolve => resolve(42));
await x;
let y = p ? 42 : new Promise(resolve => resolve(42));
await y;
“ for of”应与Iterables一起使用
如果你有一个可迭代的对象(例如数组,集合或列表),那么遍历其值的最佳选择是for of
语法。使用计数器,然后……你将获得正确的行为,但是你的代码看起来并不那么干净。
不兼容的代码示例:
const arr = [4, 3, 2, 1];
for (let i = 0; i < arr.length; i++) { // Noncompliant
console.log(arr[i]);
}
合规解决方案:
const arr = [4, 3, 2, 1];
for (let value of arr) {
console.log(value);
}
不应使用“模块”
每个文件都被视为“外部”模块。module
关键字的使用创建了一个内部模块,并且namespace
出于相同目的在ECMAScript 2015
添加之前使用了该关键字。现在namespace
可以使用了,module
因为它可以做相同的事情,所以不赞成使用它,并且使用它会使维护人员不了解该语言的历史。
不兼容的代码示例:
module myMod { // Noncompliant
// ...
}
合规解决方案:
namespace myMod {
// ...
}
使用“ Array.prototype.sort()”时应提供比较功能
无论数组中的类型如何,默认的排序顺序都是字母顺序,而不是数字顺序。具体来说,即使数组仅包含数字,数组中的所有值也将转换为字符串并按字典顺序排序,顺序如下:1、15、2、20、5
。
幸运的是,该sort
方法允许你传递可选的compare
函数以指定排序顺序。提供比较功能时,返回的顺序取决于比较功能的返回值。
不兼容的代码示例:
var myarray = [80, 3, 9, 34, 23, 5, 1];
myarray.sort();
console.log(myarray); // outputs: [1, 23, 3, 34, 5, 80, 9]
合规解决方案:
var myarray = [80, 3, 9, 34, 23, 5, 1];
myarray.sort((a, b) => (a - b));
console.log(myarray); // outputs: [1, 3, 5, 9, 23, 34, 80]
方法重载应分组在一起
为了清楚起见,应将同一方法的所有重载分组在一起。这样,用户和维护人员都可以快速了解所有当前可用的选项。
不兼容的代码示例:
interface MyInterface {
doTheThing(): number;
doTheOtherThing(): string;
doTheThing(str: string): string; // Noncompliant
}
合规解决方案:
interface MyInterface {
doTheThing(): number;
doTheThing(str: string): string;
doTheOtherThing(): string;
}
仅在构造函数中或声明时分配的私有属性应为“只读”
readonly
属性只能在类构造函数中或在声明时分配。如果类具有未标记的属性,readonly
而仅在构造函数中设置,则可能导致对该属性的预期用途产生混淆。为避免混淆,应标记此类属性readonly
以明确其预期用途,并防止将来的维护人员无意中更改其用途。
不兼容的代码示例:
class Person {
private _birthYear: number; // Noncompliant
constructor(birthYear: number) {
this._birthYear = birthYear;
}
}
合规解决方案:
class Person {
private readonly _birthYear: number;
constructor(birthYear: number) {
this._birthYear = birthYear;
}
}
包装器对象不应用于基本类型
将包装对象用于原始类型是无偿的,令人困惑的和危险的。如果使用包装对象构造函数进行类型转换,则只需删除new
关键字,即可自动获得原始值。如果使用包装对象作为向基元添加属性的方法,则应重新考虑设计。此类使用被认为是不良做法,应予以重构。
不兼容的代码示例:
let x = new Number("0");
if (x) {
alert('hi'); // Shows 'hi'.
}
合规解决方案:
let x = Number("0");
if (x) {
alert('hi');
}
没有成员的类型,“ any”和“ never”不应在类型交集中使用
相交类型将多种类型组合为一种。这使你可以将现有类型加在一起,以获得具有所需所有功能的单个类型。但是,具有没有成员的类型的交集不会更改结果类型。相反,相交的使用 any
或never
作为相交的一部分将始终导致any
或never
。几乎可以肯定这是一个错误。
不兼容的代码示例:
function foo(p: MyType & null) { // Noncompliant
// ...
}
function bar(p: MyType & any) { // Noncompliant
// ...
}
合规解决方案:
function foo(p: MyType | null) {
// ...
}
// or
function foo(p: MyType & AnotherType) {
// ...
}
function bar(p: any) {
// ...
不应使用“any”类型
变量可以声明为带或不带类型。如果声明中包含初始化,则声明为无类型的变量将被隐式键入,并且编译器类型检查将自动应用于任何类型的变量。但是,如果你使用any
“类型” 声明变量, 则你已明确告诉编译器不要进行任何类型检查,这是有风险的。
不兼容的代码示例:
let a = 42; // implicitly typed to number
let b: number = 42; // explicitly typed to number
let c: any = 42; // Noncompliant
合规解决方案:
let a = 42;
let b: number = 42;
let c: number = 42;
promise reject不应被“try”阻止捕获
由于执行的异步特性,reject
由promise抛出的异常(包括)将不会被嵌套try
块捕获。而是使用catchof
方法Promise
或将其包装在awaitexpression
中。
try-catch
语句只包含对返回的函数的调用(Promise
因此,catc
h除捕获以外,捕获其他内容的可能性较小Promise
)。
不兼容的代码示例:
function runPromise() {
return Promise.reject("rejection reason");
}
function foo() {
try { // Noncompliant, the catch clause of the 'try' will not be executed for the code inside promise
runPromise();
} catch (e) {
console.log("Failed to run promise", e);
}
}
合规解决方案:
function foo() {
runPromise().catch(e => console.log("Failed to run promise", e));
}
// or
async function foo() {
try {
await runPromise();
} catch (e) {
console.log("Failed to run promise", e);
}
}