Skip to main content
On this page

deno lint, linter

Command line usage

deno lint [OPTIONS] [files]...

Lint JavaScript/TypeScript source code.

deno lint
deno lint myfile1.ts myfile2.js

Print result as JSON:

deno lint --json

Read from stdin:

cat file.ts | deno lint -
cat file.ts | deno lint --json -

List available rules:

deno lint --rules

To ignore specific diagnostics, you can write an ignore comment on the preceding line with a rule name (or multiple):

// deno-lint-ignore no-explicit-any
// deno-lint-ignore require-await no-empty

To ignore linting on an entire file, you can add an ignore comment at the top of the file:

// deno-lint-ignore-file

Linting options Jump to heading

--compact Jump to heading

Output lint result in compact format.

--fix Jump to heading

Fix any linting errors for rules that support it.

--ignore Jump to heading

Ignore linting particular source files.

--json Jump to heading

Output lint result in JSON format.

--rules Jump to heading

List available rules.

--rules-exclude Jump to heading

Exclude lint rules.

--rules-include Jump to heading

Include lint rules.

--rules-tags Jump to heading

Use set of rules with a tag.

Options Jump to heading

--config Jump to heading

Short flag: -c

Configure different aspects of deno including TypeScript, linting, and code formatting Typically the configuration file will be called deno.json or deno.jsonc and automatically detected; in that case this flag is not necessary.

--ext Jump to heading

Specify the file extension to lint when reading from stdin.For example, use jsx to lint JSX files or tsx for TSX files.This argument is necessary because stdin input does not automatically infer the file type.Example usage: cat file.jsx | deno lint - --ext=jsx.

--no-config Jump to heading

Disable automatic loading of the configuration file.

File watching options Jump to heading

--no-clear-screen Jump to heading

Do not clear terminal screen when under watch mode.

--watch Jump to heading

Watch for file changes and restart process automatically. Only local files from entry point module graph are watched.

--watch-exclude Jump to heading

Exclude provided files/patterns from watch mode.

Available rules Jump to heading

For a complete list of supported rules, visit the deno_lint rule documentation.

adjacent-overload-signatures Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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-untagged-todo Jump to heading

Requires TODOs to be annotated with either a user tag (@user) or an issue reference (#issue).

TODOs without reference to a user or an issue become stale with no easy way to get more information.

Invalid:

// TODO Improve calc engine
export function calcValue(): number {}
// TODO Improve calc engine (@djones)
export function calcValue(): number {}
// TODO Improve calc engine (#332)
export function calcValue(): number {}

Valid:

// TODO(djones) Improve calc engine
export function calcValue(): number {}
// TODO(@djones) Improve calc engine
export function calcValue(): number {}
// TODO(#332)
export function calcValue(): number {}
// TODO(#332) Improve calc engine
export function calcValue(): number {}

ban-unused-ignore Jump to heading

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;

button-has-type Jump to heading

Checks that a <button> JSX element has a valid type attribute. The default value is "submit" which is often not the desired behavior.

Invalid:

<button />
<button type="foo" />
<button type={condition ? "foo" : "bar"} />
<button type={foo} />
<button type={2} />

Valid:

<button type="submit" />
<button type="button" />
<button type="reset" />
<button type={condition ? "button" : "submit"} />

camelcase Jump to heading

Enforces the use of camelCase in variable names

Consistency in a code base is key for readability and maintainability. This rule enforces variable declarations and object property names which you create to be in camelCase.

Of note:

  • _ is allowed at the start or end of a variable
  • All uppercase variable names (e.g. constants) may have _ in their name
  • If you have to use a snake_case key in an object for some reasons, wrap it in quotation mark
  • This rule also applies to variables imported or exported via ES modules, but not to object properties of those variables

Invalid:

let first_name = "Ichigo";
const obj1 = { last_name: "Hoshimiya" };
const obj2 = { first_name };
const { last_name } = obj1;

function do_something() {}
function foo({ snake_case = "default value" }) {}

class snake_case_class {}
class Also_Not_Valid_Class {}

import { not_camelCased } from "external-module.js";
export * as not_camelCased from "mod.ts";

enum snake_case_enum {
  snake_case_variant,
}

type snake_case_type = { some_property: number };

interface snake_case_interface {
  some_property: number;
}

Valid:

let firstName = "Ichigo";
const FIRST_NAME = "Ichigo";
const __myPrivateVariable = "Hoshimiya";
const myPrivateVariable_ = "Hoshimiya";
const obj1 = { "last_name": "Hoshimiya" }; // if an object key is wrapped in quotation mark, then it's valid
const obj2 = { "first_name": first_name };
const { last_name: lastName } = obj;

function doSomething() {} // function declarations must be camelCase but...
do_something(); // ...snake_case function calls are allowed
function foo({ snake_case: camelCase = "default value" }) {}

class PascalCaseClass {}

import { not_camelCased as camelCased } from "external-module.js";
export * as camelCased from "mod.ts";

enum PascalCaseEnum {
  PascalCaseVariant,
}

type PascalCaseType = { someProperty: number };

interface PascalCaseInterface {
  someProperty: number;
}

constructor-super Jump to heading

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 {}

default-param-last Jump to heading

Enforces default parameter(s) to be last in the function signature.

Parameters with default values are optional by nature but cannot be left out of the function call without mapping the function inputs to different parameters which is confusing and error prone. Specifying them last allows them to be left out without changing the semantics of the other parameters.

Invalid:

function f(a = 2, b) {}
function f(a = 5, b, c = 5) {}

Valid:

function f() {}
function f(a) {}
function f(a = 5) {}
function f(a, b = 5) {}
function f(a, b = 5, c = 5) {}
function f(a, b = 5, ...c) {}
function f(a = 2, b = 3) {}

eqeqeq Jump to heading

Enforces the use of type-safe equality operators === and !== instead of the more error prone == and != operators.

=== and !== ensure the comparators are of the same type as well as the same value. On the other hand == and != do type coercion before value checking which can lead to unexpected results. For example 5 == "5" is true, while 5 === "5" is false.

Invalid:

if (a == 5) {}
if ("hello world" != input) {}

Valid:

if (a === 5) {}
if ("hello world" !== input) {}

explicit-function-return-type Jump to heading

Requires all functions to have explicit return types.

Explicit return types have a number of advantages including easier to understand code and better type safety. It is clear from the signature what the return type of the function (if any) will be.

Invalid:

function someCalc() {
  return 2 * 2;
}
function anotherCalc() {
  return;
}

Valid:

function someCalc(): number {
  return 2 * 2;
}
function anotherCalc(): void {
  return;
}

explicit-module-boundary-types Jump to heading

Requires all module exports to have fully typed declarations

Having fully typed function arguments and return values clearly defines the inputs and outputs of a module (known as the module boundary). This will make it very clear to any users of the module how to supply inputs and handle outputs in a type safe manner.

Invalid:

// Missing return type (e.g. void)
export function printDoc(doc: string, doubleSided: boolean) {
  return;
}

// Missing argument type (e.g. `arg` is of type string)
export const arrowFn = (arg): string => `hello ${arg}`;

// Missing return type (e.g. boolean)
export function isValid() {
  return true;
}

Valid:

// Typed input parameters and return value
export function printDoc(doc: string, doubleSided: boolean): void {
  return;
}

// Input of type string and a return value of type string
export const arrowFn = (arg: string): string => `hello ${arg}`;

// Though lacking a return type, this is valid as it is not exported
function isValid() {
  return true;
}

for-direction Jump to heading

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 Jump to heading

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() {}

fresh-server-event-handlers Jump to heading

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 Jump to heading

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";
  }
}

guard-for-in Jump to heading

Require for-in loops to include an if statement

Looping over objects with a for-in loop will include properties that are inherited through the prototype chain. This behavior can lead to unexpected items in your for loop.

Invalid:

for (const key in obj) {
  foo(obj, key);
}

Valid:

for (const key in obj) {
  if (Object.hasOwn(obj, key)) {
    foo(obj, key);
  }
}
for (const key in obj) {
  if (!Object.hasOwn(obj, key)) {
    continue;
  }
  foo(obj, key);
}

jsx-boolean-value Jump to heading

Enforce a consistent JSX boolean value style. Passing true as the boolean value can be omitted with the shorthand syntax.

Invalid:

const foo = <Foo isFoo={true} />;
const foo = <Foo isFoo={false} />;

Valid:

const foo = <Foo isFoo />;
const foo = <Foo isFoo={false} />;

jsx-curly-braces Jump to heading

Ensure consistent use of curly braces around JSX expressions.

Invalid:

const foo = <Foo foo=<div /> />;
const foo = <Foo str={"foo"} />;
const foo = <div>{"foo"}</div>;

Valid:

const foo = <Foo foo={<div />} />;
const foo = <Foo str="foo" />;
const foo = <div>foo</div>;

jsx-key Jump to heading

Ensure the key attribute is present when passing iterables into JSX. It allows frameworks to optimize checking the order of elements.

Invalid:

const foo = [<div>foo</div>];
const foo = [<>foo</>];
[1, 2, 3].map(() => <div />);
Array.from([1, 2, 3], () => <div />);

Valid:

const foo = [<div key="a">foo</div>];
const foo = [<Fragment key="b">foo</Fragment>];
[1, 2, 3].map((x) => <div key={x} />);
Array.from([1, 2, 3], (x) => <div key={x} />);

jsx-no-children-prop Jump to heading

Pass children as JSX children instead of as an attribute.

Invalid:

<div children="foo" />
<div children={[<Foo />, <Bar />]} />

Valid:

<div>foo</div>
<div><Foo /><Bar /></div>

jsx-no-danger-with-children Jump to heading

Using JSX children together with dangerouslySetInnerHTML is invalid as they will be ignored.

Invalid:

<div dangerouslySetInnerHTML={{ __html: "<h1>hello</h1>" }}>
  <h1>this will never be rendered</h1>
</div>;

Valid:

<div dangerouslySetInnerHTML={{ __html: "<h1>hello</h1>" }} />;

jsx-no-duplicate-props Jump to heading

Disallow duplicated JSX props. Later props will always overwrite earlier props often leading to unexpected results.

Invalid:

<div id="1" id="2" />;
<App a a />;
<App a {...b} a />;

Valid:

<div id="1" />
<App a />
<App a {...b} />
<App {...b} b />

jsx-no-useless-fragment Jump to heading

Fragments are only necessary at the top of a JSX "block" and only when there are multiple children. Fragments are not needed in other scenarios.

Invalid:

<></>
<><div /></>
<><App /></>
<p>foo <>bar</></p>

Valid:

<>{foo}</>
<><div /><div /></>
<>foo <div /></>
<p>foo bar</p>

jsx-props-no-spread-multi Jump to heading

Spreading the same expression twice is typically a mistake and causes unnecessary computations.

Invalid:

<div {...foo} {...foo} />
<div {...foo} a {...foo} />
<Foo {...foo.bar} {...foo.bar} />

Valid:

<div {...foo} />
<div {...foo.bar} a />
<Foo {...foo.bar} />

jsx-void-dom-elements-no-children Jump to heading

Ensure that void elements in HTML don't have any children as that is not valid HTML. See Void element article on MDN for more information.

Invalid:

<br>foo</br>
<img src="a.jpg">foo</img>

Valid:

<br />
<img src="a.jpg" />

no-array-constructor Jump to heading

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 Jump to heading

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-loop Jump to heading

Requires await is not used in a for loop body

Async and await are used in Javascript to provide parallel execution. If each element in the for loop is waited upon using await, then this negates the benefits of using async/await as no more elements in the loop can be processed until the current element finishes.

A common solution is to refactor the code to run the loop body asynchronously and capture the promises generated. After the loop finishes you can then await all the promises at once.

Invalid:

async function doSomething(items) {
  const results = [];
  for (const item of items) {
    // Each item in the array blocks on the previous one finishing
    results.push(await someAsyncProcessing(item));
  }
  return processResults(results);
}

Valid:

async function doSomething(items) {
  const results = [];
  for (const item of items) {
    // Kick off all item processing asynchronously...
    results.push(someAsyncProcessing(item));
  }
  // ...and then await their completion after the loop
  return processResults(await Promise.all(results));
}

no-await-in-sync-fn Jump to heading

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-boolean-literal-for-arguments Jump to heading

Requires all functions called with any amount of boolean literals as parameters to use a self-documenting constant instead.

Is common to define functions that can take booleans as arguments. However, passing boolean literals as parameters can lead to lack of context regarding the role of the argument inside the function in question.

A simple fix for the points mentioned above is the use of self documenting constants that will end up working as "named booleans", that allow for a better understanding on what the parameters mean in the context of the function call.

Invalid:

function redraw(allViews: boolean, inline: boolean) {
  // redraw logic.
}
redraw(true, true);

function executeCommand(recursive: boolean, executionMode: EXECUTION_MODES) {
  // executeCommand logic.
}
executeCommand(true, EXECUTION_MODES.ONE);

function enableLogs(enable: boolean) {
  // enabledLogs logic.
}
enableLogs(true);

Valid:

function redraw(allViews: boolean, inline: boolean) {
  // redraw logic.
}
const ALL_VIEWS = true, INLINE = true;
redraw(ALL_VIEWS, INLINE);

function executeCommand(recursive: boolean, executionMode: EXECUTION_MODES) {
  // executeCommand logic.
}
const RECURSIVE = true;
executeCommand(RECURSIVE, EXECUTION_MODES.ONE);

function enableLogs(enable: boolean) {
  // enabledLogs logic.
}
const ENABLE = true;
enableLogs(ENABLE);

no-case-declarations Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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-console Jump to heading

Disallows the use of the console global.

Oftentimes, developers accidentally commit console.log/console.error statements, left in particularly after debugging. Moreover, using these in code may leak sensitive information to the output or clutter the console with unnecessary information. This rule helps maintain clean and secure code by disallowing the use of console.

This rule is especially useful in libraries where you almost never want to output to the console.

Invalid:

console.log("Debug message");
console.error("Debug message");
console.debug(obj);

if (debug) console.log("Debugging");

function log() {
  console.log("Log");
}

Valid:

It is recommended to explicitly enable the console via a deno-lint-ignore comment for any calls where you actually want to use it.

function logWarning(message: string) {
  // deno-lint-ignore no-console
  console.warn(message);
}

no-const-assign Jump to heading

Disallows modifying a variable declared as const.

Modifying a variable declared as const will result in a runtime error.

Invalid:

const a = 0;
a = 1;
a += 1;
a++;
++a;

Valid:

const a = 0;
const b = a + 1;

// `c` is out of scope on each loop iteration, allowing a new assignment
for (const c in [1, 2, 3]) {}

no-constant-condition Jump to heading

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 Jump to heading

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-danger Jump to heading

Prevent the use of dangerouslySetInnerHTML which can lead to XSS vulnerabilities if used incorrectly.

Invalid:

const hello = <div dangerouslySetInnerHTML={{ __html: "Hello World!" }} />;

Valid:

const hello = <div>Hello World!</div>;

no-debugger Jump to heading

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 Jump to heading

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 Jump to heading

Warns the usage of the deprecated - Deno APIs

The following APIs will be removed from the Deno.* namespace but have newer APIs to migrate to. See the Deno 1.x to 2.x Migration Guide for migration instructions.

  • Deno.Buffer
  • Deno.Closer
  • Deno.close()
  • Deno.Conn.rid
  • Deno.copy()
  • Deno.customInspect
  • Deno.File
  • Deno.fstatSync()
  • Deno.fstat()
  • Deno.FsWatcher.rid
  • Deno.ftruncateSync()
  • Deno.ftruncate()
  • Deno.futimeSync()
  • Deno.futime()
  • Deno.isatty()
  • Deno.Listener.rid
  • Deno.ListenTlsOptions.certFile
  • Deno.ListenTlsOptions.keyFile
  • Deno.readAllSync()
  • Deno.readAll()
  • Deno.Reader
  • Deno.ReaderSync
  • Deno.readSync()
  • Deno.read()
  • Deno.run()
  • Deno.seekSync()
  • Deno.seek()
  • Deno.serveHttp()
  • Deno.Server
  • Deno.shutdown
  • Deno.stderr.rid
  • Deno.stdin.rid
  • Deno.stdout.rid
  • Deno.TlsConn.rid
  • Deno.UnixConn.rid
  • Deno.writeAllSync()
  • Deno.writeAll()
  • Deno.Writer
  • Deno.WriterSync
  • Deno.writeSync()
  • Deno.write()
  • new Deno.FsFile()

The following APIs will be removed from the Deno.* namespace without replacement.

  • Deno.resources()
  • Deno.metrics()

no-dupe-args Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

Disallows the declaration of an empty interface

An interface with no members serves no purpose. This rule will capture these situations as either unnecessary code or a mistaken empty implementation.

Invalid:

interface Foo {}

Valid:

interface Foo {
  name: string;
}

interface Bar {
  age: number;
}

// Using an empty interface with at least one extension are allowed.

// Using an empty interface to change the identity of Baz from type to interface.
type Baz = { profession: string };
interface Foo extends Baz {}

// Using an empty interface to extend already existing Foo declaration
// with members of the Bar interface
interface Foo extends Bar {}

// Using an empty interface as a union type
interface Baz extends Foo, Bar {}

no-empty-pattern Jump to heading

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-eval Jump to heading

Disallows the use of eval

eval is a potentially dangerous function which can open your code to a number of security vulnerabilities. In addition to being slow, eval is also often unnecessary with better solutions available.

Invalid:

const obj = { x: "foo" };
const key = "x",
const value = eval("obj." + key);

Valid:

const obj = { x: "foo" };
const value = obj[x];

no-ex-assign Jump to heading

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 Jump to heading

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-external-imports Jump to heading

Disallows the use of external imports

  • what's the motivation of this lint rule?
    • this rule emits warnings if external modules are imported via URL. "deps.ts" and import maps are exception.
  • why is linted code considered bad?
    • importing external modules just works fine, but it will take time and effort when you want to upgrade those modules if they are imported in multiple places in your project.
  • who should use it?
    • to avoid it you could use "deps.ts convention" or import maps, where you import all external modules and then re-export them or assign aliases to them.
    • so if you'd like to follow the "deps.ts convention" or to use import maps, this rule is for you.

Invalid:

import { assertEquals } from "https://deno.land/std@0.126.0/testing/asserts.ts";

Valid:

import { assertEquals } from "./deps.ts";
// deps.ts

export {
  assert,
  assertEquals,
  assertStringIncludes,
} from "https://deno.land/std@0.126.0/testing/asserts.ts";

you can refer to the explanation of this convention here https://docs.deno.com/runtime/manual/basics/modules/#it-seems-unwieldy-to-import-urls-everywhere

no-extra-boolean-cast Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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-implicit-declare-namespace-export Jump to heading

Disallows the use of implicit exports in "ambient" namespaces.

TypeScript implicitly export all members of an "ambient" namespaces, except whether a named export is present.

Invalid:

// foo.ts or foo.d.ts
declare namespace ns {
  interface ImplicitlyExported {}
  export type Exported = true;
}

Valid:

// foo.ts or foo.d.ts
declare namespace ns {
  interface NonExported {}
  export {};
}

declare namespace ns {
  interface Exported {}
  export { Exported };
}

declare namespace ns {
  export interface Exported {}
}

no-import-assertions Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

Disallows defining constructors 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 Jump to heading

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 Jump to heading

Disallows the use of new operators with built-in Symbols

Symbols 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-node-globals Jump to heading

Disallows the use of NodeJS global objects.

NodeJS exposes a set of global objects that differs from deno (and the web), so code should not assume they are available. Instead, import the objects from their defining modules as needed.

Invalid:

// foo.ts
const buf = Buffer.from("foo", "utf-8"); // Buffer is not a global object in deno

Valid:

// foo.ts
import { Buffer } from "node:buffer";

const foo = Buffer.from("foo", "utf-8");

no-non-null-asserted-optional-chain Jump to heading

Disallow non-null assertions after an optional chain expression

?. optional chain expressions provide undefined if an object is null or undefined. Using a ! non-null assertion to assert the result of an ?. optional chain expression is non-nullable is likely wrong.

Invalid:

foo?.bar!;
foo?.bar()!;

Valid:

foo?.bar;
foo?.bar();

no-non-null-assertion Jump to heading

Disallow non-null assertions using the ! postfix operator

TypeScript's ! non-null assertion operator asserts to the type system that an expression is non-nullable, as in not null or undefined. Using assertions to tell the type system new information is often a sign that code is not fully type-safe. It's generally better to structure program logic so that TypeScript understands when values may be nullable.

Invalid:

interface Example {
  property?: string;
}
declare const example: Example;

const includes = example.property!.includes("foo");

Valid:

interface Example {
  property?: string;
}
declare const example: Example;

const includes = example.property?.includes("foo") ?? false;

no-obj-calls Jump to heading

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 Jump to heading

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-process-global Jump to heading

Disallows the use of NodeJS process global.

NodeJS and Deno expose process global but they are hard to statically analyze by tools, so code should not assume they are available. Instead, import process from "node:process".

Invalid:

// foo.ts
const foo = process.env.FOO;

Valid:

// foo.ts
import process from "node:process";

const foo = process.env.FOO;

no-prototype-builtins Jump to heading

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 Jump to heading

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 Jump to heading

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 Jump to heading

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-self-compare Jump to heading

Disallows comparisons where both sides are exactly the same.

Comparing a variable or value against itself is usually an error, either a typo or refactoring error. It is confusing to the reader and may potentially introduce a runtime error.

Invalid:

if (x === x) {
}
if ("x" === "x") {
}
if (a.b === a.b) {
}
if (a["b"] === a["b"]) {
}

Valid:

if (x === y) {
}
if ("x" === "y") {
}
if (a.b === a.c) {
}
if (a["b"] === a["c"]) {
}

no-setter-return Jump to heading

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 Jump to heading

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-sparse-arrays Jump to heading

Disallows sparse arrays

Sparse arrays are arrays that contain empty slots, which later could be handled either as undefined value or skipped by array methods, and this may lead to unexpected behavior:

[1, , 2].join(); // => '1,,2'
[1, undefined, 2].join(); // => '1,,2'

[1, , 2].flatMap((item) => item); // => [1, 2]
[1, undefined, 2].flatMap((item) => item); // => [1, undefined, 2]

Invalid:

const items = ["foo", , "bar"];

Valid:

const items = ["foo", "bar"];

no-sync-fn-in-async-fn Jump to heading

Disallow sync function inside async function

Using sync functions like Deno.readTextFileSync blocks the deno event loop so it's not recommended to use it inside of an async function, because it stops progress of all other async tasks.

Invalid:

async function foo() {
  Deno.readTextFileSync("");
}

const fooFn = async function foo() {
  Deno.readTextFileSync("");
};

const fooFn = async () => {
  Deno.readTextFileSync("");
};

Valid:

async function foo() {
  await Deno.readTextFile("");
}

function foo() {
  Deno.readTextFileSync("");
}

const fooFn = function foo() {
  Deno.readTextFileSync("");
};

const fooFn = () => {
  Deno.readTextFileSync("");
};

no-this-alias Jump to heading

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 Jump to heading

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-throw-literal Jump to heading

Disallow throwing literals as exceptions

It is considered good practice to only throw the Error object itself or an object using the Error object as base objects for user-defined exceptions. The fundamental benefit of Error objects is that they automatically keep track of where they were built and originated.

Invalid:

throw "error";
throw 0;
throw undefined;
throw null;

Valid:

throw new Error("error");

no-top-level-await Jump to heading

Disallows the use of top level await expressions.

Top level await cannot be used when distributing CommonJS/UMD via dnt.

Invalid:

await foo();
for await (item of items) {}

Valid:

async function foo() {
  await task();
}
async function foo() {
  for await (item of items) {}
}

no-undef Jump to heading

Disallow the use of undeclared variables

Invalid:

const foo = someFunction();
const bar = a + 1;

no-unreachable Jump to heading

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 Jump to heading

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 Jump to heading

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 operator
  • instanceof 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 Jump to heading

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 Jump to heading

Enforces all variables are 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) or let otherVariable = a;
  • it's called or constructed, like a() or new 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-useless-rename Jump to heading

Disallow useless rename operations where both the original and new name are exactly the same. This is often a leftover from a refactoring procedure and can be safely removed.

Invalid:

import { foo as foo } from "foo";
const { foo: foo } = obj;
export { foo as foo };

Valid:

import { foo as bar } from "foo";
const { foo: bar } = obj;
export { foo as bar };

no-var Jump to heading

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-global Jump to heading

Disallows the use of the window object.

The window global is no longer available in Deno. 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 Jump to heading

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 Jump to heading

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 Jump to heading

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:

  1. adding an explicit type annotation
  2. using normal type assertion (like as "foo", or <"foo">)
  3. 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-ascii Jump to heading

Ensures that the code is fully written in ASCII characters.

V8, the JavaScript engine Deno relies on, provides a method that strings get populated outside V8's heap. In particular, if they are composed of one-byte characters only, V8 can handle them much more efficiently through v8::String::ExternalOneByteStringResource. In order to leverage this V8 feature in the internal of Deno, this rule checks if all characters in the code are ASCII.

That said, you can also make use of this lint rule for something other than Deno's internal JavaScript code. If you want to make sure your codebase is made up of ASCII characters only (e.g. want to disallow non-ASCII identifiers) for some reasons, then this rule will be helpful.

Invalid:

const π = Math.PI;

// string literals are also checked
const ninja = "🥷";

function こんにちは(名前: string) {
  console.log(`こんにちは、${名前}さん`);
}

// “comments” are also checked
// ^        ^
// |        U+201D
// U+201C

Valid:

const pi = Math.PI;

const ninja = "ninja";

function hello(name: string) {
  console.log(`Hello, ${name}`);
}

// "comments" are also checked

prefer-const Jump to heading

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 Jump to heading

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" {}

prefer-primordials Jump to heading

Suggests using frozen intrinsics from primordials rather than the default globals.

This lint rule is designed to be dedicated to Deno's internal code. Normal users don't have to run this rule for their code.

Primordials are a frozen set of all intrinsic objects in the runtime, which we should use in the Deno's internal to avoid the risk of prototype pollution. This rule detects the direct use of global intrinsics and suggests replacing it with the corresponding one from the primordials object.

One such example is:

const arr = getSomeArrayOfNumbers();
const evens = arr.filter((val) => val % 2 === 0);

The second line of this example should be:

const evens = primordials.ArrayPrototypeFilter(arr, (val) => val % 2 === 0);

Invalid:

const arr = new Array();

const s = JSON.stringify({});

const i = parseInt("42");

const { ownKeys } = Reflect;

Valid:

const { Array } = primordials;
const arr = new Array();

const { JSONStringify } = primordials;
const s = JSONStringify({});

const { NumberParseInt } = primordials;
const i = NumberParseInt("42");

const { ReflectOwnKeys } = primordials;

require-await Jump to heading

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 Jump to heading

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";
}

single-var-declarator Jump to heading

Disallows multiple variable definitions in the same declaration statement

Invalid:

const foo = 1, bar = "2";

Valid:

const foo = 1;
const bar = "2";

triple-slash-reference Jump to heading

Disallow certain triple slash directives in favor of ES6-style import declarations

TypeScript's /// triple-slash references are a way to indicate that types from another module are available in a file. Use of triple-slash reference type directives is generally discouraged in favor of ECMAScript Module imports. This rule reports on the use of /// <reference path="..." />, /// <reference types="..." />, or /// <reference lib="..." /> directives.

Invalid:

/// <reference types="foo" />
import * as foo from "foo";

Valid:

import * as foo from "foo";

use-isnan Jump to heading

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 or NaN == NaN evaluate to false
  • NaN !== NaN or NaN != NaN evaluate to true

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 Jump to heading

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;

verbatim-module-syntax Jump to heading

Enforces type imports to be declared as type imports.

This rule ensures that the code works when the verbatimModuleSyntax TypeScript compiler option is enabled. This is useful in libraries distributing TypeScript code in order to work in more scenarios.

Invalid:

import { Person } from "./person.ts";

const person: Person = {
  name: "David",
};
console.log(person);
import { output, Person } from "./person.ts";

const person: Person = {
  name: "David",
};
output(person);

Valid:

import type { Person } from "./person.ts";

const person: Person = {
  name: "David",
};
console.log(person);
import { output, type Person } from "./person.ts";

const person: Person = {
  name: "David",
};
output(person);

Ignore directives Jump to heading

Files Jump to heading

To ignore the whole file, a // deno-lint-ignore-file directive should placed at the top of the file:

// deno-lint-ignore-file

function foo(): any {
  // ...
}

or

// deno-lint-ignore-file -- reason for ignoring

function foo(): any {
  // ...
}

The ignore directive must be placed before the first statement or declaration:

// Copyright 2020 the Deno authors. All rights reserved. MIT license.

/**
 * Some JS doc
 */

// deno-lint-ignore-file

import { bar } from "./bar.js";

function foo(): any {
  // ...
}

You can also ignore certain diagnostics in the whole file:

// deno-lint-ignore-file no-explicit-any no-empty

function foo(): any {
  // ...
}

Diagnostics Jump to heading

To ignore certain diagnostics, the // deno-lint-ignore <rules...> directive should be placed before the targeted line. Specifying the ignored rule name is required:

// deno-lint-ignore no-explicit-any
function foo(): any {
  // ...
}

// deno-lint-ignore no-explicit-any explicit-function-return-type
function bar(a: any) {
  // ...
}

You can also specify the reason for ignoring the diagnostic:

// deno-lint-ignore no-explicit-any -- reason for ignoring
function foo(): any {
  // ...
}

Did you find what you needed?

Privacy policy