adjacent-overload-signatures
Requires overload signatures to be adjacent to each other.
Requires overload signatures to be adjacent to each other.
Overloaded signatures which are not next to each other can lead to code which is hard to read and maintain.
Invalid:
(bar
is declared in-between foo
overloads)
type FooType = {
foo(s: string): void;
foo(n: number): void;
bar(): void;
foo(sn: string | number): void;
};
interface FooInterface {
foo(s: string): void;
foo(n: number): void;
bar(): void;
foo(sn: string | number): void;
}
class FooClass {
foo(s: string): void;
foo(n: number): void;
bar(): void {}
foo(sn: string | number): void {}
}
export function foo(s: string): void;
export function foo(n: number): void;
export function bar(): void {}
export function foo(sn: string | number): void {}
Valid:
(bar
is declared after foo
)
type FooType = {
foo(s: string): void;
foo(n: number): void;
foo(sn: string | number): void;
bar(): void;
};
interface FooInterface {
foo(s: string): void;
foo(n: number): void;
foo(sn: string | number): void;
bar(): void;
}
class FooClass {
foo(s: string): void;
foo(n: number): void;
foo(sn: string | number): void {}
bar(): void {}
}
export function foo(s: string): void;
export function foo(n: number): void;
export function foo(sn: string | number): void {}
export function bar(): void {}
ban-ts-comment
Disallows the use of Typescript directives without a comment.
Disallows the use of Typescript directives without a comment.
Typescript directives reduce the effectiveness of the compiler, something which should only be done in exceptional circumstances. The reason why should be documented in a comment alongside the directive.
Invalid:
// @ts-expect-error
let a: number = "I am a string";
// @ts-ignore
let a: number = "I am a string";
// @ts-nocheck
let a: number = "I am a string";
Valid:
// @ts-expect-error: Temporary workaround (see ticket #422)
let a: number = "I am a string";
// @ts-ignore: Temporary workaround (see ticket #422)
let a: number = "I am a string";
// @ts-nocheck: Temporary workaround (see ticket #422)
let a: number = "I am a string";
ban-types
Bans the use of primitive wrapper objects (e.g. String
the object is a wrapper
Bans the use of primitive wrapper objects (e.g. String
the object is a wrapper
of string
the primitive) in addition to the non-explicit Function
type and
the misunderstood Object
type.
There are very few situations where primitive wrapper objects are desired and far more often a mistake was made with the case of the primitive type. You also cannot assign a primitive wrapper object to a primitive leading to type issues down the line. For reference, the TypeScript handbook also says we shouldn't ever use these wrapper objects.
With Function
, it is better to explicitly define the entire function signature
rather than use the non-specific Function
type which won't give you type
safety with the function.
Finally, Object
and {}
means "any non-nullish value" rather than "any object
type". object
is a good choice for a meaning of "any object type".
Invalid:
let a: Boolean;
let b: String;
let c: Number;
let d: Symbol;
let e: Function;
let f: Object;
let g: {};
Valid:
let a: boolean;
let b: string;
let c: number;
let d: symbol;
let e: () => number;
let f: object;
let g: Record<string, never>;
ban-unknown-rule-code
Warns the usage of unknown rule codes in ignore directives
Warns the usage of unknown rule codes in ignore directives
We sometimes have to suppress and ignore lint errors for some reasons. We can do so using ignore directives with rule names that should be ignored like so:
// deno-lint-ignore no-explicit-any no-unused-vars
const foo: any = 42;
This rule checks for the validity of the specified rule names (i.e. whether
deno_lint
provides the rule or not).
Invalid:
// typo
// deno-lint-ignore eq-eq-e
console.assert(x == 42);
// unknown rule name
// deno-lint-ignore UNKNOWN_RULE_NAME
const b = "b";
Valid:
// deno-lint-ignore eq-eq-eq
console.assert(x == 42);
// deno-lint-ignore no-unused-vars
const b = "b";
ban-untagged-ignore
Requires deno-lint-ignore
to be annotated with one or more rule names.
Requires deno-lint-ignore
to be annotated with one or more rule names.
Ignoring all rules can mask unexpected or future problems. Therefore you need to explicitly specify which rule(s) are to be ignored.
Invalid:
// deno-lint-ignore
export function duplicateArgumentsFn(a, b, a) {}
Valid:
// deno-lint-ignore no-dupe-args
export function duplicateArgumentsFn(a, b, a) {}
ban-unused-ignore
Warns unused ignore directives
Warns unused ignore directives
We sometimes have to suppress and ignore lint errors for some reasons and we can do so using ignore directives.
In some cases, however, like after refactoring, we may end up having ignore directives that are no longer necessary. Such superfluous ignore directives are likely to confuse future code readers, and to make matters worse, might hide future lint errors unintentionally. To prevent such situations, this rule detects unused, superfluous ignore directives.
Invalid:
// Actually this line is valid since `export` means "used",
// so this directive is superfluous
// deno-lint-ignore no-unused-vars
export const foo = 42;
Valid:
export const foo = 42;
constructor-super
Verifies the correct usage of constructors and calls to super()
.
Verifies the correct usage of constructors and calls to super()
.
Defined constructors of derived classes (e.g. class A extends B
) must always
call super()
. Classes which extend non-constructors (e.g.
class A extends null
) must not have a constructor.
Invalid:
class A {}
class Z {
constructor() {}
}
class B extends Z {
constructor() {} // missing super() call
}
class C {
constructor() {
super(); // Syntax error
}
}
class D extends null {
constructor() {} // illegal constructor
}
class E extends null {
constructor() { // illegal constructor
super();
}
}
Valid:
class A {}
class B extends A {}
class C extends A {
constructor() {
super();
}
}
class D extends null {}
for-direction
Requires for
loop control variables to increment in the correct direction
Requires for
loop control variables to increment in the correct direction
Incrementing for
loop control variables in the wrong direction leads to
infinite loops. This can occur through incorrect initialization, bad
continuation step logic or wrong direction incrementing of the loop control
variable.
Invalid:
// Infinite loop
for (let i = 0; i < 2; i--) {}
Valid:
for (let i = 0; i < 2; i++) {}
fresh-handler-export
Checks correct naming for named fresh middleware export
Checks correct naming for named fresh middleware export
Files inside the routes/
folder can export middlewares that run before any
rendering happens. They are expected to be available as a named export called
handler
. This rule checks for when the export was incorrectly named handlers
instead of handler
.
Invalid:
export const handlers = {
GET() {},
POST() {},
};
export function handlers() {}
export async function handlers() {}
Valid:
export const handler = {
GET() {},
POST() {},
};
export function handler() {}
export async function handler() {}
Disallows event handlers in fresh server components
Disallows event handlers in fresh server components
Components inside the routes/
folder in a fresh app are exclusively rendered
on the server. They are not rendered in the client and setting an event handler
will have no effect.
Note that this rule only applies to server components inside the routes/
folder, not to fresh islands or any other components.
Invalid:
<button onClick={() => {}} />
<button onclick={() => {}} />
<my-custom-element foo={() => {}} />
Valid:
<button />
<my-custom-element />
getter-return
Requires all property getter functions to return a value
Requires all property getter functions to return a value
Getter functions return the value of a property. If the function returns no value then this contract is broken.
Invalid:
let foo = {
get bar() {},
};
class Person {
get name() {}
}
Valid:
let foo = {
get bar() {
return true;
},
};
class Person {
get name() {
return "alice";
}
}
no-array-constructor
Enforce conventional usage of array construction
Enforce conventional usage of array construction
Array construction is conventionally done via literal notation such as []
or
[1, 2, 3]
. Using the new Array()
is discouraged as is new Array(1, 2, 3)
.
There are two reasons for this. The first is that a single supplied argument
defines the array length, while multiple arguments instead populate the array of
no fixed size. This confusion is avoided when pre-populated arrays are only
created using literal notation. The second argument to avoiding the Array
constructor is that the Array
global may be redefined.
The one exception to this rule is when creating a new array of fixed size, e.g.
new Array(6)
. This is the conventional way to create arrays of fixed length.
Invalid:
// This is 4 elements, not a size 100 array of 3 elements
const a = new Array(100, 1, 2, 3);
const b = new Array(); // use [] instead
Valid:
const a = new Array(100);
const b = [];
const c = [1, 2, 3];
no-async-promise-executor
Requires that async promise executor functions are not used
Requires that async promise executor functions are not used
Promise constructors take an executor function as an argument with resolve
and
reject
parameters that can be used to control the state of the created
Promise. This function is allowed to be async but this is generally not a good
idea for several reasons:
- If an async executor function throws an error, the error will be lost and won't cause the newly-constructed Promise to reject. This could make it difficult to debug and handle some errors.
- If an async Promise executor function is using await, then this is usually a sign that it is not actually necessary to use the new Promise constructor and the code can be restructured to avoid the use of a promise, or the scope of the new Promise constructor can be reduced, extracting the async code and changing it to be synchronous.
Invalid:
new Promise(async function (resolve, reject) {});
new Promise(async (resolve, reject) => {});
Valid:
new Promise(function (resolve, reject) {});
new Promise((resolve, reject) => {});
no-await-in-sync-fn
Disallow await
keyword inside a non-async function
Disallow await
keyword inside a non-async function
Using the await
keyword inside a non-async function is a syntax error. To be
able to use await
inside a function, the function needs to be marked as async
via the async
keyword
Invalid:
function foo() {
await bar();
}
const fooFn = function foo() {
await bar();
};
const fooFn = () => {
await bar();
};
Valid:
async function foo() {
await bar();
}
const fooFn = async function foo() {
await bar();
};
const fooFn = async () => {
await bar();
};
no-case-declarations
Requires lexical declarations (let
, const
, function
and class
) in switch
Requires lexical declarations (let
, const
, function
and class
) in switch
case
or default
clauses to be scoped with brackets.
Without brackets in the case
or default
block, the lexical declarations are
visible to the entire switch block but only get initialized when they are
assigned, which only happens if that case/default is reached. This can lead to
unexpected errors. The solution is to ensure each case
or default
block is
wrapped in brackets to scope limit the declarations.
Invalid:
switch (choice) {
// `let`, `const`, `function` and `class` are scoped the entire switch statement here
case 1:
let a = "choice 1";
break;
case 2:
const b = "choice 2";
break;
case 3:
function f() {
return "choice 3";
}
break;
default:
class C {}
}
Valid:
switch (choice) {
// The following `case` and `default` clauses are wrapped into blocks using brackets
case 1: {
let a = "choice 1";
break;
}
case 2: {
const b = "choice 2";
break;
}
case 3: {
function f() {
return "choice 3";
}
break;
}
default: {
class C {}
}
}
no-class-assign
Disallows modifying variables of class declarations
Disallows modifying variables of class declarations
Declaring a class such as class A {}
, creates a variable A
. Like any
variable this can be modified or reassigned. In most cases this is a mistake and
not what was intended.
Invalid:
class A {}
A = 0; // reassigning the class variable itself
Valid:
class A {}
let c = new A();
c = 0; // reassigning the variable `c`
no-compare-neg-zero
Disallows comparing against negative zero (-0
).
Disallows comparing against negative zero (-0
).
Comparing a value directly against negative may not work as expected as it will
also pass for non-negative zero (i.e. 0
and +0
). Explicit comparison with
negative zero can be performed using Object.is
.
Invalid:
if (x === -0) {}
Valid:
if (x === 0) {}
if (Object.is(x, -0)) {}
no-cond-assign
Disallows the use of the assignment operator, =
, in conditional statements.
Disallows the use of the assignment operator, =
, in conditional statements.
Use of the assignment operator within a conditional statement is often the
result of mistyping the equality operator, ==
. If an assignment within a
conditional statement is required then this rule allows it by wrapping the
assignment in parentheses.
Invalid:
let x;
if (x = 0) {
let b = 1;
}
function setHeight(someNode) {
do {
someNode.height = "100px";
} while (someNode = someNode.parentNode);
}
Valid:
let x;
if (x === 0) {
let b = 1;
}
function setHeight(someNode) {
do {
someNode.height = "100px";
} while ((someNode = someNode.parentNode));
}
no-constant-condition
Disallows the use of a constant expression in conditional test
Disallows the use of a constant expression in conditional test
Using a constant expression in a conditional test is often either a mistake or a temporary situation introduced during development and is not ready for production.
Invalid:
if (true) {}
if (2) {}
do {} while (x = 2); // infinite loop
Valid:
if (x) {}
if (x === 0) {}
do {} while (x === 2);
no-control-regex
Disallows the use ascii control characters in regular expressions
Disallows the use ascii control characters in regular expressions
Control characters are invisible characters in the ASCII range of 0-31. It is uncommon to use these in a regular expression and more often it is a mistake in the regular expression.
Invalid:
// Examples using ASCII (31) Carriage Return (hex x0d)
const pattern1 = /\x0d/;
const pattern2 = /\u000d/;
const pattern3 = new RegExp("\\x0d");
const pattern4 = new RegExp("\\u000d");
Valid:
// Examples using ASCII (32) Space (hex x20)
const pattern1 = /\x20/;
const pattern2 = /\u0020/;
const pattern3 = new RegExp("\\x20");
const pattern4 = new RegExp("\\u0020");
no-debugger
Disallows the use of the debugger
statement
Disallows the use of the debugger
statement
debugger
is a statement which is meant for stopping the javascript execution
environment and start the debugger at the statement. Modern debuggers and
tooling no longer need this statement and leaving it in can cause the execution
of your code to stop in production.
Invalid:
function isLongString(x: string) {
debugger;
return x.length > 100;
}
Valid:
function isLongString(x: string) {
return x.length > 100; // set breakpoint here instead
}
no-delete-var
Disallows the deletion of variables
Disallows the deletion of variables
delete
is used to remove a property from an object. Variables declared via
var
, let
and const
cannot be deleted (delete
will return false
).
Setting strict
mode on will raise a syntax error when attempting to delete a
variable.
Invalid:
const a = 1;
let b = 2;
let c = 3;
delete a; // would return false
delete b; // would return false
delete c; // would return false
Valid:
let obj = {
a: 1,
};
delete obj.a; // return true
no-deprecated-deno-api
Warns the usage of the deprecated Deno APIs
Warns the usage of the deprecated Deno APIs
The following APIs in Deno
namespace are now marked as deprecated and will get
removed from the namespace in the future.
IO APIs
Deno.Buffer
Deno.copy
Deno.iter
Deno.iterSync
Deno.readAll
Deno.readAllSync
Deno.writeAll
Deno.writeAllSync
The IO APIs are already available in std/io
or std/streams
, so replace these
deprecated ones with alternatives from std
. For more detail, see
the tracking issue.
Sub Process API
Deno.run
Deno.run
was deprecated in favor of Deno.Command
. See
deno#9435 for more details.
Custom Inspector API
Deno.customInspect
Deno.customInspect
was deprecated in favor of
Symbol.for("Deno.customInspect")
. Replace the usages with this symbol
expression. See deno#9294 for
more details.
File system API
Deno.File
Deno.File
was deprecated in favor of Deno.FsFile
. Replace the usages with
new class name.
Invalid:
// buffer
const a = Deno.Buffer();
// read
const b = await Deno.readAll(reader);
const c = Deno.readAllSync(reader);
// write
await Deno.writeAll(writer, data);
Deno.writeAllSync(writer, data);
// iter
for await (const x of Deno.iter(xs)) {}
for (const y of Deno.iterSync(ys)) {}
// copy
await Deno.copy(reader, writer);
// custom inspector
class A {
[Deno.customInspect]() {
return "This is A";
}
}
function foo(file: Deno.File) {
// ...
}
Valid:
// readAll
import { toArrayBuffer } from "https://deno.land/std/streams/to_array_buffer.ts";
const b = await toArrayBuffer(reader); // `b` is ArrayBuffer
const c = new Uint8Array(b); // You can convert ArrayBuffer to Uint8Array
// writeAll
// reader is `ReadableStream` and writer is `WritableStream`
const reader = ReadableStream.from([1, 2, 3]);
await reader.pipeTo(writer);
// iter
// reader is `ReadableStream`
for await (const chunk of reader) {
// do something
}
// copy
// reader is `ReadableStream` and writer is `WritableStream`
await reader.pipeTo(writer);
// custom inspector
class A {
[Symbol.for("Deno.customInspect")]() {
return "This is A";
}
}
function foo(file: Deno.FsFile) {
// ...
}
no-dupe-args
Disallows using an argument name more than once in a function signature
Disallows using an argument name more than once in a function signature
If you supply multiple arguments of the same name to a function, the last instance will shadow the preceding one(s). This is most likely an unintentional typo.
Invalid:
function withDupes(a, b, a) {
console.log("I'm the value of the second a:", a);
}
Valid:
function withoutDupes(a, b, c) {
console.log("I'm the value of the first (and only) a:", a);
}
no-dupe-class-members
Disallows using a class member function name more than once
Disallows using a class member function name more than once
Declaring a function of the same name twice in a class will cause the previous declaration(s) to be overwritten, causing unexpected behaviors.
Invalid:
class Foo {
bar() {}
bar() {}
}
Valid:
class Foo {
bar() {}
fizz() {}
}
no-dupe-else-if
Disallows using the same condition twice in an if
/else if
statement
Disallows using the same condition twice in an if
/else if
statement
When you reuse a condition in an if
/else if
statement, the duplicate
condition will never be reached (without unusual side-effects) meaning this is
almost always a bug.
Invalid:
if (a) {}
else if (b) {}
else if (a) {} // duplicate of condition above
if (a === 5) {}
else if (a === 6) {}
else if (a === 5) {} // duplicate of condition above
Valid:
if (a) {}
else if (b) {}
else if (c) {}
if (a === 5) {}
else if (a === 6) {}
else if (a === 7) {}
no-dupe-keys
Disallows duplicate keys in object literals.
Disallows duplicate keys in object literals.
Setting the same key multiple times in an object literal will override other assignments to that key and can cause unexpected behaviour.
Invalid:
const foo = {
bar: "baz",
bar: "qux",
};
const foo = {
"bar": "baz",
bar: "qux",
};
const foo = {
0x1: "baz",
1: "qux",
};
Valid:
const foo = {
bar: "baz",
quxx: "qux",
};
no-duplicate-case
Disallows using the same case clause in a switch statement more than once
Disallows using the same case clause in a switch statement more than once
When you reuse a case test expression in a switch
statement, the duplicate
case will never be reached meaning this is almost always a bug.
Invalid:
const someText = "a";
switch (someText) {
case "a": // (1)
break;
case "b":
break;
case "a": // duplicate of (1)
break;
default:
break;
}
Valid:
const someText = "a";
switch (someText) {
case "a":
break;
case "b":
break;
case "c":
break;
default:
break;
}
no-empty
Disallows the use of empty block statements.
Disallows the use of empty block statements.
Empty block statements are legal but often represent that something was missed and can make code less readable. This rule ignores block statements that only contain comments. This rule also ignores empty constructors and function bodies (including arrow functions).
Invalid:
if (foo) {}
while (foo) {}
switch (foo) {}
try {
doSomething();
} catch (e) {
} finally {
}
Valid:
if (foo) {
// empty
}
while (foo) {
/* empty */
}
try {
doSomething();
} catch (e) {
// continue regardless of error
}
try {
doSomething();
} finally {
/* continue regardless of error */
}
no-empty-character-class
Disallows using the empty character class in a regular expression
Disallows using the empty character class in a regular expression
Regular expression character classes are a series of characters in brackets,
e.g. [abc]
. if nothing is supplied in the brackets it will not match anything
which is likely a typo or mistake.
Invalid:
/^abc[]/.test("abcdefg"); // false, as `d` does not match an empty character class
"abcdefg".match(/^abc[]/); // null
Valid:
// Without a character class
/^abc/.test("abcdefg"); // true
"abcdefg".match(/^abc/); // ["abc"]
// With a valid character class
/^abc[a-z]/.test("abcdefg"); // true
"abcdefg".match(/^abc[a-z]/); // ["abcd"]
no-empty-enum
Disallows the declaration of an empty enum
Disallows the declaration of an empty enum
An enum with no members serves no purpose. This rule will capture these situations as either unnecessary code or a mistaken empty implementation.
Invalid:
enum Foo {}
Valid:
enum Foo {
ONE = "ONE",
}
no-empty-interface
Disallows the declaration of an empty interface
Disallows the declaration of an empty interface
An interface with no members serves no purpose. Either the interface extends another interface, in which case the supertype can be used, or it does not extend a supertype in which case it is the equivalent to an empty object. This rule will capture these situations as either unnecessary code or a mistaken empty implementation.
Invalid:
interface Foo {}
interface Foo extends Bar {}
Valid:
interface Foo {
name: string;
}
interface Bar {
age: number;
}
// Using an empty interface as a union type is allowed
interface Baz extends Foo, Bar {}
no-empty-pattern
Disallows the use of empty patterns in destructuring
Disallows the use of empty patterns in destructuring
In destructuring, it is possible to use empty patterns such as {}
or []
which have no effect, most likely not what the author intended.
Invalid:
// In these examples below, {} and [] are not object literals or empty arrays,
// but placeholders for destructured variable names
const {} = someObj;
const [] = someArray;
const {a: {}} = someObj;
const [a: []] = someArray;
function myFunc({}) {}
function myFunc([]) {}
Valid:
const { a } = someObj;
const [a] = someArray;
// Correct way to default destructured variable to object literal
const { a = {} } = someObj;
// Correct way to default destructured variable to empty array
const [a = []] = someArray;
function myFunc({ a }) {}
function myFunc({ a = {} }) {}
function myFunc([a]) {}
function myFunc([a = []]) {}
no-ex-assign
Disallows the reassignment of exception parameters
Disallows the reassignment of exception parameters
There is generally no good reason to reassign an exception parameter. Once reassigned the code from that point on has no reference to the error anymore.
Invalid:
try {
someFunc();
} catch (e) {
e = true;
// can no longer access the thrown error
}
Valid:
try {
someFunc();
} catch (e) {
const anotherVar = true;
}
no-explicit-any
Disallows use of the any
type
Disallows use of the any
type
Use of the any
type disables the type check system around that variable,
defeating the purpose of Typescript which is to provide type safe code.
Additionally, the use of any
hinders code readability, since it is not
immediately clear what type of value is being referenced. It is better to be
explicit about all types. For a more type-safe alternative to any
, use
unknown
if you are unable to choose a more specific type.
Invalid:
const someNumber: any = "two";
function foo(): any {
return undefined;
}
Valid:
const someNumber: string = "two";
function foo(): undefined {
return undefined;
}
no-extra-boolean-cast
Disallows unnecessary boolean casts
Disallows unnecessary boolean casts
In certain contexts, such as if
, while
or for
statements, expressions are
automatically coerced into a boolean. Therefore, techniques such as double
negation (!!foo
) or casting (Boolean(foo)
) are unnecessary and produce the
same result as without the negation or casting.
Invalid:
if (!!foo) {}
if (Boolean(foo)) {}
while (!!foo) {}
for (; Boolean(foo);) {}
Valid:
if (foo) {}
while (foo) {}
for (; foo;) {}
no-extra-non-null-assertion
Disallows unnecessary non-null assertions
Disallows unnecessary non-null assertions
Non-null assertions are specified with an !
saying to the compiler that you
know this value is not null. Specifying this operator more than once in a row,
or in combination with the optional chaining operator (?
) is confusing and
unnecessary.
Invalid:
const foo: { str: string } | null = null;
const bar = foo!!.str;
function myFunc(bar: undefined | string) {
return bar!!;
}
function anotherFunc(bar?: { str: string }) {
return bar!?.str;
}
Valid:
const foo: { str: string } | null = null;
const bar = foo!.str;
function myFunc(bar: undefined | string) {
return bar!;
}
function anotherFunc(bar?: { str: string }) {
return bar?.str;
}
no-fallthrough
Disallows the implicit fallthrough of case statements
Disallows the implicit fallthrough of case statements
Case statements without a break
will execute their body and then fallthrough
to the next case or default block and execute this block as well. While this is
sometimes intentional, many times the developer has forgotten to add a break
statement, intending only for a single case statement to be executed. This rule
enforces that you either end each case statement with a break statement or an
explicit comment that fallthrough was intentional. The fallthrough comment must
contain one of fallthrough
, falls through
or fall through
.
Invalid:
switch (myVar) {
case 1:
console.log("1");
case 2:
console.log("2");
}
// If myVar = 1, outputs both `1` and `2`. Was this intentional?
Valid:
switch (myVar) {
case 1:
console.log("1");
break;
case 2:
console.log("2");
break;
}
// If myVar = 1, outputs only `1`
switch (myVar) {
case 1:
console.log("1");
/* falls through */
case 2:
console.log("2");
}
// If myVar = 1, intentionally outputs both `1` and `2`
no-func-assign
Disallows the overwriting/reassignment of an existing function
Disallows the overwriting/reassignment of an existing function
Javascript allows for the reassignment of a function definition. This is generally a mistake on the developers part, or poor coding practice as code readability and maintainability will suffer.
Invalid:
function foo() {}
foo = bar;
const a = function baz() {
baz = "now I'm a string";
};
myFunc = existingFunc;
function myFunc() {}
Valid:
function foo() {}
const someVar = foo;
const a = function baz() {
const someStr = "now I'm a string";
};
const anotherFuncRef = existingFunc;
let myFuncVar = function () {};
myFuncVar = bar; // variable reassignment, not function re-declaration
no-global-assign
Disallows assignment to native Javascript objects
Disallows assignment to native Javascript objects
In Javascript, String
and Object
for example are native objects. Like any
object, they can be reassigned, but it is almost never wise to do so as this can
lead to unexpected results and difficult to track down bugs.
Invalid:
Object = null;
undefined = true;
window = {};
no-import-assertions
Disallows the assert
keyword for import attributes
Disallows the assert
keyword for import attributes
ES import attributes (previously called import assertions) has been changed to
use the with
keyword. The old syntax using assert
is still supported, but
deprecated.
Invalid:
import obj from "./obj.json" assert { type: "json" };
import("./obj2.json", { assert: { type: "json" } });
Valid:
import obj from "./obj.json" with { type: "json" };
import("./obj2.json", { with: { type: "json" } });
no-import-assign
Disallows reassignment of imported module bindings
Disallows reassignment of imported module bindings
ES module import bindings should be treated as read-only since modifying them during code execution will likely result in runtime errors. It also makes for poor code readability and difficult maintenance.
Invalid:
import defaultMod, { namedMod } from "./mod.js";
import * as modNameSpace from "./mod2.js";
defaultMod = 0;
namedMod = true;
modNameSpace.someExportedMember = "hello";
modNameSpace = {};
Valid:
import defaultMod, { namedMod } from "./mod.js";
import * as modNameSpace from "./mod2.js";
// properties of bound imports may be set
defaultMod.prop = 1;
namedMod.prop = true;
modNameSpace.someExportedMember.prop = "hello";
no-inferrable-types
Disallows easily inferrable types
Disallows easily inferrable types
Variable initializations to JavaScript primitives (and null
) are obvious in
their type. Specifying their type can add additional verbosity to the code. For
example, with const x: number = 5
, specifying number
is unnecessary as it is
obvious that 5
is a number.
Invalid:
const a: bigint = 10n;
const b: bigint = BigInt(10);
const c: boolean = true;
const d: boolean = !0;
const e: number = 10;
const f: number = Number("1");
const g: number = Infinity;
const h: number = NaN;
const i: null = null;
const j: RegExp = /a/;
const k: RegExp = RegExp("a");
const l: RegExp = new RegExp("a");
const m: string = "str";
const n: string = `str`;
const o: string = String(1);
const p: symbol = Symbol("a");
const q: undefined = undefined;
const r: undefined = void someValue;
class Foo {
prop: number = 5;
}
function fn(s: number = 5, t: boolean = true) {}
Valid:
const a = 10n;
const b = BigInt(10);
const c = true;
const d = !0;
const e = 10;
const f = Number("1");
const g = Infinity;
const h = NaN;
const i = null;
const j = /a/;
const k = RegExp("a");
const l = new RegExp("a");
const m = "str";
const n = `str`;
const o = String(1);
const p = Symbol("a");
const q = undefined;
const r = void someValue;
class Foo {
prop = 5;
}
function fn(s = 5, t = true) {}
no-inner-declarations
Disallows variable or function definitions in nested blocks
Disallows variable or function definitions in nested blocks
Function declarations in nested blocks can lead to less readable code and potentially unexpected results due to compatibility issues in different JavaScript runtimes. This does not apply to named or anonymous functions which are valid in a nested block context.
Variables declared with var
in nested blocks can also lead to less readable
code. Because these variables are hoisted to the module root, it is best to
declare them there for clarity. Note that variables declared with let
or
const
are block scoped and therefore this rule does not apply to them.
Invalid:
if (someBool) {
function doSomething() {}
}
function someFunc(someVal: number): void {
if (someVal > 4) {
var a = 10;
}
}
Valid:
function doSomething() {}
if (someBool) {}
var a = 10;
function someFunc(someVal: number): void {
var foo = true;
if (someVal > 4) {
let b = 10;
const fn = function doSomethingElse() {};
}
}
no-invalid-regexp
Disallows specifying invalid regular expressions in RegExp constructors
Disallows specifying invalid regular expressions in RegExp constructors
Specifying an invalid regular expression literal will result in a SyntaxError at compile time, however specifying an invalid regular expression string in the RegExp constructor will only be discovered at runtime.
Invalid:
const invalidRegExp = new RegExp(")");
Valid:
const goodRegExp = new RegExp(".");
no-invalid-triple-slash-reference
Warns the wrong usage of triple-slash reference directives.
Warns the wrong usage of triple-slash reference directives.
Deno supports the triple-slash reference directives of types
, path
, lib
,
and no-default-lib
. This lint rule checks if there is an invalid, badly-formed
directive because it is most likely a mistake.
Additionally, note that only the types
directive is allowed in JavaScript
files. This directive is useful for telling the TypeScript compiler the location
of a type definition file that corresponds to a certain JavaScript file.
However, even in the Deno manual of the versions prior to v1.10 (e.g. v1.9.2),
there was a wrong statement describing that one should use the path
directive
in such cases. Actually, the types
directive should be used. See
the latest manual for more detail. So this rule also detects the usage of the
directive other than types
in JavaScript files and suggests replacing it with
the types
directive.
Invalid:
JavaScript
/// <reference path="./mod.d.ts" />
/// <reference no-default-lib="true" />
/// <reference foo="bar" />
// ... the rest of the JavaScript ...
TypeScript
/// <reference foo="bar" />
// ... the rest of the TypeScript ...
Valid:
JavaScript
/// <reference types="./mod.d.ts" />
/// <reference lib="es2017.string" />
// ... the rest of the JavaScript ...
TypeScript
/// <reference types="./mod.d.ts" />
/// <reference path="./mod.d.ts" />
/// <reference lib="es2017.string" />
/// <reference no-default-lib="true" />
// ... the rest of the TypeScript ...
no-irregular-whitespace
Disallows the use of non-space or non-tab whitespace characters
Disallows the use of non-space or non-tab whitespace characters
Non-space or non-tab whitespace characters can be very difficult to spot in your code as editors will often render them invisibly. These invisible characters can cause issues or unexpected behaviors. Sometimes these characters are added inadvertently through copy/paste or incorrect keyboard shortcuts.
The following characters are disallowed:
\u000B - Line Tabulation (\v) - <VT>
\u000C - Form Feed (\f) - <FF>
\u00A0 - No-Break Space - <NBSP>
\u0085 - Next Line
\u1680 - Ogham Space Mark
\u180E - Mongolian Vowel Separator - <MVS>
\ufeff - Zero Width No-Break Space - <BOM>
\u2000 - En Quad
\u2001 - Em Quad
\u2002 - En Space - <ENSP>
\u2003 - Em Space - <EMSP>
\u2004 - Tree-Per-Em
\u2005 - Four-Per-Em
\u2006 - Six-Per-Em
\u2007 - Figure Space
\u2008 - Punctuation Space - <PUNCSP>
\u2009 - Thin Space
\u200A - Hair Space
\u200B - Zero Width Space - <ZWSP>
\u2028 - Line Separator
\u2029 - Paragraph Separator
\u202F - Narrow No-Break Space
\u205f - Medium Mathematical Space
\u3000 - Ideographic Space
To fix this linting issue, replace instances of the above with regular spaces, tabs or new lines. If it's not obvious where the offending character(s) are try retyping the line from scratch.
no-misused-new
Disallows defining constructor
s for interfaces or new
for classes
Disallows defining constructor
s for interfaces or new
for classes
Specifying a constructor
for an interface or defining a new
method for a
class is incorrect and should be avoided.
Invalid:
class C {
new(): C;
}
interface I {
constructor(): void;
}
Valid:
class C {
constructor() {}
}
interface I {
new (): C;
}
no-namespace
Disallows the use of namespace
and module
keywords in TypeScript code.
Disallows the use of namespace
and module
keywords in TypeScript code.
namespace
and module
are both thought of as outdated keywords to organize
the code. Instead, it is generally preferable to use ES2015 module syntax (e.g.
import
/export
).
However, this rule still allows the use of these keywords in the following two cases:
- they are used for defining "ambient" namespaces along with
declare
keywords - they are written in TypeScript's type definition files:
.d.ts
Invalid:
// foo.ts
module mod {}
namespace ns {}
// bar.d.ts
// all usage of `module` and `namespace` keywords are allowed in `.d.ts`
Valid:
// foo.ts
declare global {}
declare module mod1 {}
declare module "mod2" {}
declare namespace ns {}
// bar.d.ts
module mod1 {}
namespace ns1 {}
declare global {}
declare module mod2 {}
declare module "mod3" {}
declare namespace ns2 {}
no-new-symbol
Disallows the use of new
operators with built-in Symbol
s
Disallows the use of new
operators with built-in Symbol
s
Symbol
s are created by being called as a function, but we sometimes call it
with the new
operator by mistake. This rule detects such wrong usage of the
new
operator.
Invalid:
const foo = new Symbol("foo");
Valid:
const foo = Symbol("foo");
function func(Symbol: typeof SomeClass) {
// This `Symbol` is not built-in one
const bar = new Symbol();
}
no-obj-calls
Disallows calling built-in global objects like functions
Disallows calling built-in global objects like functions
The following built-in objects should not be invoked like functions, even though they look like constructors:
Math
JSON
Reflect
Atomics
Calling these as functions would result in runtime errors. This rule statically prevents such wrong usage of them.
Invalid:
const math = Math();
const newMath = new Math();
const json = JSON();
const newJSON = new JSON();
const reflect = Reflect();
const newReflect = new Reflect();
const atomics = Atomics();
const newAtomics = new Atomics();
Valid:
const area = (radius: number): number => Math.PI * radius * radius;
const parsed = JSON.parse("{ foo: 42 }");
const x = Reflect.get({ x: 1, y: 2 }, "x");
const first = Atomics.load(foo, 0);
no-octal
Disallows expressing octal numbers via numeric literals beginning with 0
Disallows expressing octal numbers via numeric literals beginning with 0
Octal numbers can be expressed via numeric literals with leading 0
like 042
,
but this expression often confuses programmers. That's why ECMAScript's strict
mode throws SyntaxError
for the expression.
Since ES2015, the other prefix 0o
has been introduced as an alternative. This
new one is always encouraged to use in today's code.
Invalid:
const a = 042;
const b = 7 + 042;
Valid:
const a = 0o42;
const b = 7 + 0o42;
const c = "042";
no-prototype-builtins
Disallows the use of Object.prototype
builtins directly
Disallows the use of Object.prototype
builtins directly
If objects are created via Object.create(null)
they have no prototype
specified. This can lead to runtime errors when you assume objects have
properties from Object.prototype
and attempt to call the following methods:
hasOwnProperty
isPrototypeOf
propertyIsEnumerable
Instead, it's always encouraged to call these methods from Object.prototype
explicitly.
Invalid:
const a = foo.hasOwnProperty("bar");
const b = foo.isPrototypeOf("bar");
const c = foo.propertyIsEnumerable("bar");
Valid:
const a = Object.prototype.hasOwnProperty.call(foo, "bar");
const b = Object.prototype.isPrototypeOf.call(foo, "bar");
const c = Object.prototype.propertyIsEnumerable.call(foo, "bar");
no-redeclare
Disallows redeclaration of variables, functions, parameters with the same name.
Disallows redeclaration of variables, functions, parameters with the same name.
JavaScript allows us to redeclare variables with the same name using var
, but
redeclaration should not be used since it can make variables hard to trace.
In addition, this lint rule disallows redeclaration using let
or const
as
well, although ESLint allows. This is useful because we can notice a syntax
error before actually running the code.
As for functions and parameters, JavaScript just treats these as runtime errors,
throwing SyntaxError
when being run. It's also beneficial to detect this sort
of errors statically.
Invalid:
var a = 3;
var a = 10;
let b = 3;
let b = 10;
const c = 3;
const c = 10;
function d() {}
function d() {}
function e(arg: number) {
var arg: number;
}
function f(arg: number, arg: string) {}
Valid:
var a = 3;
function f() {
var a = 10;
}
if (foo) {
let b = 2;
} else {
let b = 3;
}
no-regex-spaces
Disallows multiple spaces in regular expression literals.
Disallows multiple spaces in regular expression literals.
Multiple spaces in regular expression literals are generally hard to read when
the regex gets complicated. Instead, it's better to use only one space character
and specify how many times spaces should appear with the {n}
syntax, for
example:
// Multiple spaces in the regex literal are harder to understand how many
// spaces are expected to be matched
const re = /foo bar/;
// Instead use `{n}` syntax for readability
const re = /foo {3}var/;
Invalid:
const re1 = / /;
const re2 = /foo bar/;
const re3 = / a b c d /;
const re4 = /foo {3}bar/;
const re5 = new RegExp(" ");
const re6 = new RegExp("foo bar");
const re7 = new RegExp(" a b c d ");
const re8 = new RegExp("foo {3}bar");
Valid:
const re1 = /foo/;
const re2 = / /;
const re3 = / {3}/;
const re4 = / +/;
const re5 = / ?/;
const re6 = / */;
const re7 = new RegExp("foo");
const re8 = new RegExp(" ");
const re9 = new RegExp(" {3}");
const re10 = new RegExp(" +");
const re11 = new RegExp(" ?");
const re12 = new RegExp(" *");
no-self-assign
Disallows self assignments
Disallows self assignments
Self assignments like a = a;
have no effect at all. If there are self
assignments in the code, most likely it means that the author is still in the
process of refactoring and there's remaining work they have to do.
Invalid:
a = a;
[a] = [a];
[a, b] = [a, b];
[a, b] = [a, c];
[a, ...b] = [a, ...b];
a.b = a.b;
Valid:
let a = a;
a += a;
a = [a];
[a, b] = [b, a];
a.b = a.c;
no-setter-return
Disallows returning values from setters.
Disallows returning values from setters.
Setters are supposed to be used for setting some value to the property, which means that returning a value from a setter makes no sense. In fact, returned values are ignored and cannot ever be used at all although returning a value from a setter produces no error. This is why static check for this mistake by the linter is quite beneficial.
Note that returning without a value is allowed; this is a useful technique to do early-return from a function.
Invalid:
const a = {
set foo(x: number) {
return "something";
},
};
class B {
private set foo(x: number) {
return "something";
}
}
const c = {
set foo(x: boolean) {
if (x) {
return 42;
}
},
};
Valid:
// return without a value is allowed since it is used to do early-return
const a = {
set foo(x: number) {
if (x % 2 == 0) {
return;
}
},
};
// not a setter, but a getter
class B {
get foo() {
return 42;
}
}
// not a setter
const c = {
set(x: number) {
return "something";
},
};
no-shadow-restricted-names
Disallows shadowing of restricted names.
Disallows shadowing of restricted names.
The following (a) properties of the global object, or (b) identifiers are "restricted" names in JavaScript:
These names are NOT reserved in JavaScript, which means that nothing prevents
one from assigning other values into them (i.e. shadowing). In other words, you
are allowed to use, say, undefined
as an identifier or variable name. (For
more details see MDN)
function foo() {
const undefined = "bar";
console.log(undefined); // output: "bar"
}
Of course, shadowing like this most likely confuse other developers and should be avoided. This lint rule detects and warn them.
Invalid:
const undefined = 42;
function NaN() {}
function foo(Infinity) {}
const arguments = () => {};
try {
} catch (eval) {}
Valid:
// If not assigned a value, `undefined` may be shadowed
const undefined;
const Object = 42;
function foo(a: number, b: string) {}
try {
} catch (e) {}
no-this-alias
Disallows assigning variables to this
.
Disallows assigning variables to this
.
In most cases, storing a reference to this
in a variable could be avoided by
using arrow functions properly, since they establish this
based on the scope
where the arrow function is defined.
Let's take a look at a concrete example:
const obj = {
count: 0,
doSomethingLater() {
setTimeout(function () { // this function executes on the global scope; `this` evalutes to `globalThis`
this.count++;
console.log(this.count);
}, 300);
},
};
obj.doSomethingLater();
// `NaN` is printed, because the property `count` is not in the global scope.
In the above example, this
in the function passed to setTimeout
evaluates to
globalThis
, which results in the expected value 1
not being printed.
If you wanted to work around it without arrow functions, you would store a
reference to this
in another variable:
const obj = {
count: 0,
doSomethingLater() {
const self = this; // store a reference to `this` in `self`
setTimeout(function () {
// use `self` instead of `this`
self.count++;
console.log(self.count);
}, 300);
},
};
obj.doSomethingLater();
// `1` is printed as expected
But in this case arrow functions come in handy. With arrow functions, the code becomes way clearer and easier to understand:
const obj = {
count: 0,
doSomethingLater() {
setTimeout(() => { // pass an arrow function
// `this` evaluates to `obj` here
this.count++;
console.log(this.count);
}, 300);
},
};
obj.doSomethingLater();
// `1` is printed as expected
This example is taken from MDN.
Invalid:
const self = this;
function foo() {
const self = this;
}
const bar = () => {
const self = this;
};
Valid:
const self = "this";
const [foo] = this;
no-this-before-super
Disallows use of this
or super
before calling super()
in constructors.
Disallows use of this
or super
before calling super()
in constructors.
The access to this
or super
before calling super()
in the constructor of
derived classes leads to ReferenceError
. To prevent it, this lint rule
checks if there are accesses to this
or super
before calling super()
in
constructors.
Invalid:
class A extends B {
constructor() {
this.foo = 0;
super();
}
}
class C extends D {
constructor() {
super.foo();
super();
}
}
Valid:
class A extends B {
constructor() {
super();
this.foo = 0;
}
}
class C extends D {
constructor() {
super();
super.foo();
}
}
class E {
constructor() {
this.foo = 0;
}
}
no-unreachable
Disallows the unreachable code after the control flow statements.
Disallows the unreachable code after the control flow statements.
Because the control flow statements (return
, throw
, break
and continue
)
unconditionally exit a block of code, any statements after them cannot be
executed.
Invalid:
function foo() {
return true;
console.log("done");
}
function bar() {
throw new Error("Oops!");
console.log("done");
}
while (value) {
break;
console.log("done");
}
throw new Error("Oops!");
console.log("done");
function baz() {
if (Math.random() < 0.5) {
return;
} else {
throw new Error();
}
console.log("done");
}
for (;;) {}
console.log("done");
Valid
function foo() {
return bar();
function bar() {
return 1;
}
}
no-unsafe-finally
Disallows the use of control flow statements within finally
blocks.
Disallows the use of control flow statements within finally
blocks.
Use of the control flow statements (return
, throw
, break
and continue
)
overrides the usage of any control flow statements that might have been used in
the try
or catch
blocks, which is usually not the desired behaviour.
Invalid:
let foo = function () {
try {
return 1;
} catch (err) {
return 2;
} finally {
return 3;
}
};
let foo = function () {
try {
return 1;
} catch (err) {
return 2;
} finally {
throw new Error();
}
};
Valid:
let foo = function () {
try {
return 1;
} catch (err) {
return 2;
} finally {
console.log("hola!");
}
};
no-unsafe-negation
Disallows the usage of negation operator !
as the left operand of relational
Disallows the usage of negation operator !
as the left operand of relational
operators.
!
operators appearing in the left operand of the following operators will
sometimes cause an unexpected behavior because of the operator precedence:
in
operatorinstanceof
operator
For example, when developers write a code like !key in someObject
, most likely
they want it to behave just like !(key in someObject)
, but actually it behaves
like (!key) in someObject
. This lint rule warns such usage of !
operator so
it will be less confusing.
Invalid:
if (!key in object) {}
if (!foo instanceof Foo) {}
Valid:
if (!(key in object)) {}
if (!(foo instanceof Foo)) {}
if ((!key) in object) {}
if ((!foo) instanceof Foo) {}
no-unused-labels
Disallows unused labels.
Disallows unused labels.
A label that is declared but never used is most likely developer's mistake. If that label is meant to be used, then write a code so that it will be used. Otherwise, remove the label.
Invalid:
LABEL1:
while (true) {
console.log(42);
}
LABEL2:
for (let i = 0; i < 5; i++) {
console.log(42);
}
LABEL3:
for (const x of xs) {
console.log(x);
}
Valid:
LABEL1:
while (true) {
console.log(42);
break LABEL1;
}
LABEL2:
for (let i = 0; i < 5; i++) {
console.log(42);
continue LABEL2;
}
for (const x of xs) {
console.log(x);
}
no-unused-vars
Enforces all variables used at least once.
Enforces all variables used at least once.
If there are variables that are declared but not used anywhere, it's most likely because of incomplete refactoring. This lint rule detects and warns such unused variables.
Variable a
is considered to be "used" if any of the following conditions are
satisfied:
- its value is read out, like
console.log(a)
orlet otherVariable = a;
- it's called or constructed, like
a()
ornew a()
- it's exported, like
export const a = 42;
If a variable is just assigned to a value but never read out, then it's considered to be "not used".
let a;
a = 42;
// `a` is never read out
If you want to declare unused variables intentionally, prefix them with the
underscore character _
, like _a
. This rule ignores variables that are
prefixed with _
.
Invalid:
const a = 0;
const b = 0; // this `b` is never used
function foo() {
const b = 1; // this `b` is used
console.log(b);
}
foo();
let c = 2;
c = 3;
// recursive function calls are not considered to be used, because only when `d`
// is called from outside the function body can we say that `d` is actually
// called after all.
function d() {
d();
}
// `x` is never used
export function e(x: number): number {
return 42;
}
const f = "unused variable";
Valid:
const a = 0;
console.log(a);
const b = 0;
function foo() {
const b = 1;
console.log(b);
}
foo();
console.log(b);
let c = 2;
c = 3;
console.log(c);
function d() {
d();
}
d();
export function e(x: number): number {
return x + 42;
}
export const f = "exported variable";
no-var
Enforces the use of block scoped variables over more error prone function scoped
Enforces the use of block scoped variables over more error prone function scoped
variables. Block scoped variables are defined using const
and let
keywords.
const
and let
keywords ensure the variables defined using these keywords are
not accessible outside their block scope. On the other hand, variables defined
using var
keyword are only limited by their function scope.
Invalid:
var foo = "bar";
Valid:
const foo = 1;
let bar = 2;
no-window
Disallows the use of the window
object.
Disallows the use of the window
object.
Using the window
global is deprecated and scheduled for removal in Deno 2.0.
Deno does not have a window and typeof window === "undefined"
is often used to
tell if the code is running in the browser.
Invalid:
const a = await window.fetch("https://deno.land");
const b = window.Deno.metrics();
console.log(window);
window.addEventListener("load", () => {
console.log("Loaded.");
});
Valid:
const a1 = await fetch("https://deno.land");
const a2 = await globalThis.fetch("https://deno.land");
const a3 = await self.fetch("https://deno.land");
const b1 = Deno.metrics();
const b2 = globalThis.Deno.metrics();
const b3 = self.Deno.metrics();
console.log(globalThis);
addEventListener("load", () => {
console.log("Loaded.");
});
no-window-prefix
Disallows the use of Web APIs via the window
object.
Disallows the use of Web APIs via the window
object.
In most situations, the global variable window
works like globalThis
. For
example, you could call the fetch
API like window.fetch(..)
instead of
fetch(..)
or globalThis.fetch(..)
. In Web Workers, however, window
is not
available, but instead self
, globalThis
, or no prefix work fine. Therefore,
for compatibility between Web Workers and other contexts, it's highly
recommended to not access global properties via window
.
Some APIs, including window.alert
, window.location
and window.history
, are
allowed to call with window
because these APIs are not supported or have
different meanings in Workers. In other words, this lint rule complains about
the use of window
only if it's completely replaceable with self
,
globalThis
, or no prefix.
Invalid:
const a = await window.fetch("https://deno.land");
const b = window.Deno.metrics();
Valid:
const a1 = await fetch("https://deno.land");
const a2 = await globalThis.fetch("https://deno.land");
const a3 = await self.fetch("https://deno.land");
const b1 = Deno.metrics();
const b2 = globalThis.Deno.metrics();
const b3 = self.Deno.metrics();
// `alert` is allowed to call with `window` because it's not supported in Workers
window.alert("🍣");
// `location` is also allowed
window.location.host;
no-with
Disallows the usage of with
statements.
Disallows the usage of with
statements.
The with
statement is discouraged as it may be the source of confusing bugs
and compatibility issues. For more details, see with - JavaScript | MDN.
Invalid:
with (someVar) {
console.log("foo");
}
prefer-as-const
Recommends using const assertion (as const
) over explicitly specifying literal
Recommends using const assertion (as const
) over explicitly specifying literal
types or using type assertion.
When declaring a new variable of a primitive literal type, there are three ways:
- adding an explicit type annotation
- using normal type assertion (like
as "foo"
, or<"foo">
) - using const assertion (
as const
)
This lint rule suggests using const assertion because it will generally lead to a safer code. For more details about const assertion, see the official handbook.
Invalid:
let a: 2 = 2; // type annotation
let b = 2 as 2; // type assertion
let c = <2> 2; // type assertion
let d = { foo: 1 as 1 }; // type assertion
Valid:
let a = 2 as const;
let b = 2 as const;
let c = 2 as const;
let d = { foo: 1 as const };
let x = 2;
let y: string = "hello";
let z: number = someVariable;
prefer-const
Recommends declaring variables with [const
] over [let
].
Recommends declaring variables with [const
] over [let
].
Since ES2015, JavaScript supports let
and const
for declaring variables.
If variables are declared with let
, then they become mutable; we can set
other values to them afterwards. Meanwhile, if declared with const
, they are
immutable; we cannot perform re-assignment to them.
In general, to make the codebase more robust, maintainable, and readable, it is
highly recommended to use const
instead of let
wherever possible. The
fewer mutable variables are, the easier it should be to keep track of the
variable states while reading through the code, and thus it is less likely to
write buggy code. So this lint rule checks if there are let
variables that
could potentially be declared with const
instead.
Note that this rule does not check for var
variables. Instead,
the no-var
rule is responsible for detecting
and warning var
variables.
Invalid:
let a = 0;
let b = 0;
someOperation(b);
// `const` could be used instead
for (let c in someObject) {}
// `const` could be used instead
for (let d of someArray) {}
// variable that is uninitialized at first and then assigned in the same scope is NOT allowed
// because we could simply write it like `const e = 2;` instead
let e;
e = 2;
Valid:
// uninitialized variable is allowed
let a;
let b = 0;
b += 1;
let c = 0;
c = 1;
// variable that is uninitialized at first and then assigned in the same scope _two or more times_ is allowed
// because we cannot represent it with `const`
let d;
d = 2;
d = 3;
const e = 0;
// `f` is mutated through `f++`
for (let f = 0; f < someArray.length; f++) {}
// variable that is initialized (or assigned) in another scope is allowed
let g;
function func1() {
g = 42;
}
// conditionally initialized variable is allowed
let h;
if (trueOrFalse) {
h = 0;
}
prefer-namespace-keyword
Recommends the use of namespace
keyword over module
keyword when declaring
Recommends the use of namespace
keyword over module
keyword when declaring
TypeScript module.
TypeScript supports the module
keyword for organizing code, but this wording
can lead to a confusion with the ECMAScript's module. Since TypeScript v1.5, it
has provided us with the alternative keyword namespace
, encouraging us to
always use namespace
instead whenever we write TypeScript these days. See
TypeScript v1.5 release note
for more details.
Invalid:
module modA {}
declare module modB {}
Valid:
namespace modA {}
// "ambient modules" are allowed
// https://www.typescriptlang.org/docs/handbook/modules.html#ambient-modules
declare module "modB";
declare module "modC" {}
require-await
Disallows async functions that have no await expression or await using
Disallows async functions that have no await expression or await using
declaration
In general, the primary reason to use async functions is to use await expressions or await using declarations inside. If an async function has neither, it is most likely an unintentional mistake.
Invalid:
async function f1() {
doSomething();
}
const f2 = async () => {
doSomething();
};
const f3 = async () => doSomething();
const obj = {
async method() {
doSomething();
},
};
class MyClass {
async method() {
doSomething();
}
}
Valid:
await asyncFunction();
function normalFunction() {
doSomething();
}
async function f1() {
await asyncFunction();
}
const f2 = async () => {
await asyncFunction();
};
const f3 = async () => await asyncFunction();
async function f4() {
for await (const num of asyncIterable) {
console.log(num);
}
}
async function f5() {
using = createResource();
}
// empty functions are valid
async function emptyFunction() {}
const emptyArrowFunction = async () => {};
// generators are also valid
async function* gen() {
console.log(42);
}
require-yield
Disallows generator functions that have no yield
.
Disallows generator functions that have no yield
.
JavaScript provides generator functions expressed as function*
, where we can
pause and later resume the function execution at the middle points. At these
points we use the yield
keyword. In other words, it makes no sense at all to
create generator functions that contain no yield
keyword, since such functions
could be written as normal functions.
Invalid:
function* f1() {
return "f1";
}
Valid:
function* f1() {
yield "f1";
}
// generator function with empty body is allowed
function* f2() {}
function f3() {
return "f3";
}
use-isnan
Disallows comparisons to NaN
.
Disallows comparisons to NaN
.
Because NaN
is unique in JavaScript by not being equal to anything, including
itself, the results of comparisons to NaN
are confusing:
NaN === NaN
orNaN == NaN
evaluate tofalse
NaN !== NaN
orNaN != NaN
evaluate totrue
Therefore, this rule makes you use the isNaN()
or Number.isNaN()
to judge
the value is NaN
or not.
Invalid:
if (foo == NaN) {
// ...
}
if (foo != NaN) {
// ...
}
switch (NaN) {
case foo:
// ...
}
switch (foo) {
case NaN:
// ...
}
Valid:
if (isNaN(foo)) {
// ...
}
if (!isNaN(foo)) {
// ...
}
valid-typeof
Restricts the use of the typeof
operator to a specific set of string literals.
Restricts the use of the typeof
operator to a specific set of string literals.
When used with a value the typeof
operator returns one of the following
strings:
"undefined"
"object"
"boolean"
"number"
"string"
"function"
"symbol"
"bigint"
This rule disallows comparison with anything other than one of these string
literals when using the typeof
operator, as this likely represents a typing
mistake in the string. The rule also disallows comparing the result of a
typeof
operation with any non-string literal value, such as undefined
, which
can represent an inadvertent use of a keyword instead of a string. This includes
comparing against string variables even if they contain one of the above values
as this cannot be guaranteed. An exception to this is comparing the results of
two typeof
operations as these are both guaranteed to return on of the above
strings.
Invalid:
// typo
typeof foo === "strnig";
typeof foo == "undefimed";
typeof bar != "nunber";
typeof bar !== "fucntion";
// compare with non-string literals
typeof foo === undefined;
typeof bar == Object;
typeof baz === anotherVariable;
typeof foo == 5;
Valid:
typeof foo === "undefined";
typeof bar == "object";
typeof baz === "string";
typeof bar === typeof qux;