Variables declared with let can only be reassigned by code below the
declaration. The assignment will crash with a ReferenceError if you assign to
the variable.
function getNumberOfChocolates() { return 3; }
let shouldEatChocolates = true;
if (shouldEatChocolates) {
chocolates = 0;
}
let chocolates = getNumberOfChocolates();
To fix this error, move the declaration above the assignment:
function getNumberOfChocolates() { return 3; }
let shouldEatChocolates = true;
let chocolates = getNumberOfChocolates();
if (shouldEatChocolates) {
chocolates = 0;
}
You cannot reassign variables declared with const, and you cannot reference a
variable declared with const above its declaration. The assignment will crash
with a ReferenceError if you run the code.
let timeElapsed = 31;
let pie = "cooking";
if (timeElapsed > 30) {
pi = "cooked";
}
const pi = 3.14;
To fix this error, assign to a different variable or declare a new variable with
a different name:
let timeElapsed = 31;
let pie = "cooking";
if (timeElapsed > 30) {
pie = "cooked";
}
const pi = 3.14;
export function let() {
console.log("access permitted");
}
To fix this error, name the function something other than let, or declare the
function separately with a different name and use export-as:
export function allow() {
console.log("access permitted");
}
function allowAccess() {
console.log("access permitted");
}
export { allowAccess as let };
A function or variable name includes a Unicode escape sequence, and the escape sequence
refers to a character which isn't allowed in a function or variable name:
let guitar\u2604 = "\uD83C\uDFB8";
let handc\uffed = true;
To fix this error, use the code point of a Unicode character which is allowed,
or remove the extraneous backslash from the name:
let guitar\u3604 = "\uD83C\uDFB8";
let handcuffed = true;
The initial character in a function or variable name can be any of the
following:
ID_Start
$
_
Characters after the initial character in a function or variable name can be
any of the following:
In variable names and strings, a Unicode escape sequence must contain only
hexadecimal digits (any of 0123456789abcdefABCDEF). It is an error if other
characters appear within a Unicode escape sequence:
console.log("List of Pok\ue9mon by weight:");
console.log("{Nidoran\u{2642male}");
For an escape sequence without { and }, add { and }:
console.log("List of Pok\u{e9}mon by weight:");
Alternatively, for an escape sequence without { and }, include 0 digits
such that the escape sequence contains exactly four hexadecimal digits:
console.log("List of Pok\u00e9mon by weight:");
For an escape sequence with { and }, ensure the } appears after the
hexadecimal digits:
JSX tag names and attributes can contain Unicode escape sequences starting with
\u. It is a syntax error for a Unicode escape sequence to resolve to the -
character (U+002D):
function Font() {
return <svg:font\u{2d}face font\u002dfamily="Helvetica Standard" />;
}
To fix this error, write - instead of \u{2d} or \u002d:
function Font() {
return <svg:font-face font-family="Helvetica Standard" />;
}
In JavaScript, you can assign to variables or properties. It is a syntax error
to assign to something different, such as the result of a function call or the
result of math:
function saveAccount(account, {name, pass}) {
account.checkPassword(pass);
account.getName() = name;
account.getPassword() = pass;
account.save();
}
for (let step of steps) {
if (step.index+1 = stopNumber) {
break;
}
doStep(step);
}
To fix this error, assign to a variable or property instead, or call a method to
do the assignment:
An object literal entry must either be a key: value pair, a method, or
variable short-hand. It is an error to use the short-hand syntax with anything
except a variable name:
// A tasty enum
const FRUITS = {
"BANANA",
"ORANGE",
"STRAWBERRY",
"KIWI",
};
// Pre-computed for speed
let smallPrimes = {2, 3, 5, 7, 11, 13, 17, 19};
To fix this error, either use the key: value pair syntax, or use [] to
create an array literal instead of an object literal:
JavaScript files are normally encoded using UTF-8. It is an error for a
UTF-8 JavaScript file to contain bytes which are not valid UTF-8.
quick-lint-js only supports UTF-8 JavaScript files. UTF-16, ISO-8859-1, and
other encodings are not supported by quick-lint-js. Save your file as UTF-8 to
check it with quick-lint-js.
Outside a string or template literal, Unicode escape sequences (like \u{65})
can be used in identifiers. However, Unicode escape sequences are not allowed if
they would make an identifier look like a keyword when unescaped:
let \u{69}\u{66} = "if";
let which = \u{66}inally;
To fix this error, either pick a different variable name, or make a string:
let _\u{69}\u{66} = "if";
let which = "\u{66}inally";
Binary operators (such as * and >>) require an expression (e.g. a variable
or number) on both sides of the operator. Unary operators require an expression
before or after the operator (depending on the operator). Ternary operators
require three expressions. With some exceptions, it is an error to exclude an
expression:
let ripe = true;
let tasty = true;
if (ripe && ) {
console.log("delicious!")+;
}
To fix this error, add an expression, or remove the extraneous operator:
let ripe = true;
let tasty = true;
if (ripe && tasty) {
console.log("delicious!");
}
Note that sometimes, it appears that expressions can be omitted, but some
operators are binary and unary, and some operators look like other operators
conjoined. In these cases, the code might be completely valid, so quick-lint-js
won't report any error:
3**5 // different than: 3 * * 5
3<<5 // different than: 3 < < 5
7 + - 8 // same as: 7 + (-8)
In a given function or {} block, a variable can only be declared multiple
times if it is declared with var or function. Other types of variables can
be declared only once:
let x, y, y, w;
const friends = loadFriends();
const friends = friends
.filter(friend => friend.name !== "strager");
class Orange { name = "orange" }
class Orange { name = "banana" }
function jump(player, height) {
let height = height || player.height/2;
}
To fix this error, assign to the existing variable, choose a different variable
name, or delete the extra variable:
let x, y, z, w;
let friends = loadFriends();
friends = friends
.filter(friend => friend.name !== "strager");
class Orange { name = "orange" }
class Banana { name = "banana" }
function jump(player, height) {
height = height || player.height/2;
}
Identifiers can contain Unicode escape sequences starting with \u. It is a
syntax error to write \u{ followed by hexadecimal digits without a closing
}:
let guitar\u{3604 = "\u{D83C}\u{";
To fix this error, write } to close the escape sequence.
Regular expression literals start with / and end with /. The / symbol is
also used for the division operator. It is a syntax error to omit the trailing
/ from a regular expression literal:
// The final / is escaped by \.
let LINE_CONTINUATION_RE = / +\/m;
function feetToCentimeters(feet) {
// The / is interpreted as the start of a
// regular expression, not the division
// operator.
return / 3.28 * 100;
}
To fix this error, close the regular expression literal:
let LINE_CONTINUATION_RE = / +\\/m;
Alternatively, include an expression before / to treat the / as a division
operator:
function feetToCentimeters(feet) {
return feet / 3.28 * 100;
}
String literals start with " or ' and end with " or ', respectively.
It is a syntax error to omit the trailing " or ' from a string literal. A
missing terminator can happen for a number of reasons:
// The final " is escaped by \.
let temp = "c:\temp\";
// String literals cannot span multiple lines.
// Poem by Ian Johnson.
let poem = "My code fails. I do not know why.
My code works. I do not know why.";
let unfinishedThought = "The solution is
To fix this error, ensure a backslash (\) is not escaping the terminator,
use a template literal for multi-line strings, or just include a terminator:
let temp = "c:\\temp\\";
// Poem by Ian Johnson.
let poem = `My code fails. I do not know why.
My code works. I do not know why.`;
let unfinishedThought = "The solution is";
Identifiers (variable names, etc.) can contain Unicode escape sequences
(\u{69} for example). It is an error for an identifier to have a backslash
which is not part of a Unicode escape sequence:
function identity\(x) { return x; }
let bird\U3600 = new ChirpSound();
To fix this error, remove the backslash, or complete the Unicode escape
sequence:
function identity(x) { return x; }
let bird\u3600 = new ChirpSound();
Letters are allowed in number literals in certain situations, such as in
123n, 1e6, and 0xff. It is an error to include other letters or letters in
the wrong spot:
let gazillion = 10000000000000000000000000N;
let pi = 3.14l;
let tau = 2pi;
To fix this error, use the correct letter or remove the extraneous letter:
let gazillion = 10000000000000000000000000n;
let pi = 3.14;
Alternatively, use the * operator to multiply a variable by a number:
JavaScript treats some Unicode control characters, such as newlines, tabs, and
form feeds, as whitespace. Most other control characters are now allowed outside
string literals and template literals:
To fix this error, delete the extra control characters, or put them inside a
comment:
Binary number literals start with 0b and can only contain 0 or 1 digits
(and optionally an n to signify a BigInt). It is an error to include other
digits in binary number literals:
let minInt16 = 0b1000000000000000N;
let mouse = [0xf09f, 0b196];
To fix this error, fix or remove the extra digits or letters:
let minInt16 = 0b1000000000000000n;
Alternatively, convert the binary number literal into a decimal, hexadecimal, or
octal number literal:
Octal number literals start with 0 or 0o and can only contain digits 0
through 7 (and optionally an n to signify a BigInt). It is an error to
include other digits in octal number literals:
let permissions = 0o755N;
let bcdDigits = 0o0123456789;
let million = 0o1e6;
To fix this error, fix or remove the extra digits or letters:
let permissions = 0o755n;
Alternatively, convert the octal number literal into a decimal or hexadecimal
number literal:
Hexadecimal (hex) number literals start with 0x and can only contain digits
0 through 9 and a through f (and optionally an n to signify a
BigInt). It is an error to include other letters in hex number literals:
let hungry = 0xfeedme;
To fix this error, fix or remove the extra digits or letters:
In JavaScript, # is used for shebangs at the beginning of a file (e.g.
#!/usr/bin/env node) and private properties. (# does not start a comment.)
It is an error to use # anywhere else:
Variables can be declared in many ways. For variables declared with class,
const, or let, it is an error to use the variable before/above its
declaration:
let firstName = person.firstName;
if (firstName === "") {
firstName = lastName;
}
let lastName = person.lastName;
function printAdjacentPairs(items) {
let first = true;
for (let current of items) {
if (!first) {
console.log(previous, current);
}
let previous = current;
first = false;
}
}
To fix this error, move the variable's declaration up above its use:
let firstName = person.firstName;
let lastName = person.lastName;
if (firstName === "") {
firstName = lastName;
}
Alternatively, declare the variable in an outer scope:
function printAdjacentPairs(items) {
let first = true;
let previous;
for (let current of items) {
if (!first) {
console.log(previous, current);
}
previous = current;
first = false;
}
}
String literals and template literals can contain escape sequences, including
\x followed by two hexadecimal digits. It is an error for \x to be followed
by anything except two hexadecimal digits:
let gameTitle = isBlue
? 'Pok\xmon Blue'
: 'Pok\xe9mon Red';
let path = 'c:\xampp\bin\apache.exe';
To fix this error, complete the sequence by writing two hexadecimal digits:
let gameTitle = isBlue
? 'Pok\xe9mon Blue'
: 'Pok\xe9mon Red';
If a statement begins with the function keyword, the declared function must
have a name. It is an error to start a statement with function but not give a
name to the function:
function (number) {
return number % 2 === 0;
}
To fix this error, write the name of the function after the function keyword:
function isEven(number) {
return number % 2 === 0;
}
If a statement begins with the function keyword, the declared function must
have a name. It is an error to start a statement with function but not give a
name to the function:
function() { // IIFE for our module
class PublicClass {}
class PrivateClass {}
window.PublicClass = PublicClass;
}()
function (number) {
return number % 2 === 0;
}
[1, 2, 3, 4].filter(isEven)
.forEach(number => console.log(number));
To fix this error, wrap the IIFE (Immediately Invoked Function Expression) in
parentheses:
(function() { // IIFE for our module
class PublicClass {}
class PrivateClass {}
window.PublicClass = PublicClass;
}())
Alternatively, write the name of the function after the function keyword:
function isEven(number) {
return number % 2 === 0;
}
[1, 2, 3, 4].filter(isEven)
.forEach(number => console.log(number));
if statements require a body, which must be a statement or {} surrounding
a list of statements. It is a syntax error to omit the body of an if
statement:
function assert(condition) {
if (!condition)
}
if (rose.color === 'red' &&
violet.color === 'blue')
To fix this error, write the body of the if statement:
function assert(condition) {
if (!condition)
throw new AssertionError();
}
if (rose.color === 'red' &&
violet.color === 'blue') {
sugar.flavor = 'sweet';
}
When exporting a class, function, or variable, you must either export while
declaring or export separately from declaring. When exporting separately, it is
a syntax error to write export followed by the name of the thing you want to
export:
class Person {}
export Person;
To fix this error, add { and } around the exported names:
class Person {}
export {Person};
Alternatively, write the default keyword after export:
In a function declaration, an extra , can be added to the end of the parameter
list. However, it is a syntax error to include an extra , after a spread
parameter:
In non-strict mode, a variable can be named yield. In strict mode and inside
generator functions, it is a syntax error to use yield as a variable name:
function *mapRange(end, f) {
for (let i = 0; i < end; ++i) {
const
yield item;
}
}
To fix this error, complete the variable declaration preceeding yield:
function *mapRange(f, end) {
for (let i = 0; i < end; ++i) {
const item = f(i);
yield item;
}
}
Functions declared with function can have zero or more parameters. It is a
syntax error to omit the parameter list, including ( and ), even if the
function has no parameters:
class Doge {
speak {
console.log('many woofie');
}
}
function visitDogPark {
new Doge().speak();
}
setInterval(
function {
visitDogPark();
},
1000,
);
To fix this error, add a pair of parentheses before { in the function:
class Doge {
speak() {
console.log('many woofie');
}
}
function visitDogPark() {
new Doge().speak();
}
setInterval(
function() {
visitDogPark();
},
1000,
);
In modules, you can declare and export a variable at the same time. However, it
is a syntax error to declare and export a variable by default:
export default let cache = {};
To fix this error, export by name, not by default:
// Import using:
// import {cache} from "./cache.mjs";
export let cache = {};
Alternatively, to export by default, declare the variable then export it in a
separate statement. Note that this means importers of the variable cannot assign
to the variable (but the object can still be modified):
// Import using:
// import cache from "./cache.mjs";
let cache = {};
export default cache;
If a statement begins with the class keyword, the declared class must have a
name. It is a syntax error to start a statement with class but not give a name
to the class:
class {
speak() {
console.log('woof!');
}
}
To fix this error, write the name of the class after the class keyword:
class Doggie {
speak() {
console.log('woof!');
}
}
Alternatively, declare a variable and initialize it with the class:
const Doggie = class {
speak() {
console.log('woof!');
}
};
If a variable is named async, it is a syntax error to assign to that variable
in a for-of loop:
async function awaitSequentially(asyncs) {
let results = [];
let async;
for (async of asyncs) {
results.push(await async);
}
return results;
}
To fix this error, declare the variable inside the for-of loop:
async function awaitSequentially(asyncs) {
let results = [];
for (let async of asyncs) {
results.push(await async);
}
return results;
}
Alternatively, rename the variable to something other than async:
async function awaitSequentially(promises) {
let results = [];
let promise;
for (promise of promises) {
results.push(await promise);
}
return results;
}
Object literals support a short-hand syntax which allows you to omit the value
of a property. It is a syntax error to omit the value if the key is computed or
is a keyword:
let class_ = classes.join(" ");
React.createElement(
'div',
{ class },
children,
);
To fix this error, explicitly write a value for the property:
C-style for loops have three components, each separated by ;: an
initializer, a condition expression, and an update expression. It is a syntax
error to write only two of these three components:
for (let i = 0; i < 100) {
console.log(i % 15 ? i : "FizzBuzz");
}
To fix this error, write the missing component:
for (let i = 0; i < 100; ++i) {
console.log(i % 15 ? i : "FizzBuzz");
}
C-style for loops, for-in loops, and for-of loops require a body,
which must be a statement or {} surrounding a list of statements. It is a
syntax error to omit the body of a for loop:
function skipNumber(parser) {
for (; parser.isDigit(); parser.next())
}
To fix this error, write the body of the for loop:
function skipNumber(parser) {
for (; parser.isDigit(); parser.next()) {}
}
There are three kinds of for loops: C-style for loops (;), for-in
loops, and for-of loops. It is a syntax error to write a for loop without
;, in, or of:
for (queue.length > 0) {
process(queue.pop());
}
To fix this error, use a while loop instead of a for loop:
while (queue.length > 0) {
process(queue.pop());
}
There are three kinds of for loops: C-style for loops (;), for-in
loops, and for-of loops. It is a syntax error to write a for loop without
;, in, or of:
for (const enemy) {
enemy.health -= damage;
}
for (let i) {
console.log(i % 15 ? i : "FizzBuzz");
}
To fix this error, write in or of followed by an iterable (such as an
array):
for (const enemy of collidedEntities) {
enemy.health -= damage;
}
Alternatively, write the remainder of the C-style for loop:
for (let i = 0; i < 100; ++i) {
console.log(i % 15 ? i : "FizzBuzz");
}
C-style for loops require two semicolons: one ; between the init and the
condition, and one ; between the condition and the update expression. It is a
syntax error to omit the ; between the init and the condition:
let i;
for (i = 0 i < 100; ++i) {
console.log(i % 15 ? i : "FizzBuzz");
}
To fix this error, insert a semicolon (;) before the condition:
let i;
for (i = 0; i < 100; ++i) {
console.log(i % 15 ? i : "FizzBuzz");
}
C-style for loops require two semicolons: one ; between the init and the
condition, and one ; between the condition and the update expression. It is a
syntax error to omit the ; between the condition and the update expression:
for (let i = 0; i < 100 ++i) {
console.log(i % 15 ? i : "FizzBuzz");
}
To fix this error, insert a semicolon (;) after the condition:
for (let i = 0; i < 100; ++i) {
console.log(i % 15 ? i : "FizzBuzz");
}
do-while loops require a body, which must be a statement or {}
surrounding a list of statements. It is a syntax error to omit the body of a
do-while loop:
function skipNumber(parser) {
do
while (isDigit(parser.peek()));
}
do while (queue.length > 0) {
queue.pop().run();
}
To fix this error, write the body of the do-while loop:
function skipNumber(parser) {
do parser.next();
while (isDigit(parser.peek()));
}
C-style for loops have three components, each separated by ;: an
initializer, a condition expression, and an update expression. It is a syntax
error to write more than three components:
for (let x = 0, y = 0;
x < width && y < height;
++x;
++y) {
draw(x, y, pixelAt(x, y));
}
To fix this error, use , instead of ; to separate expressions in the update
clause:
for (let x = 0, y = 0;
x < width && y < height;
++x, ++y) {
draw(x, y, pixelAt(x, y));
}
A do-while loop has three parts: the do keyword, a body (a statement, or a
list of statements surrounded by { and }), and the while part including
the condition. It is a syntax error to write the do keyword without the
while part:
let name;
do {
name = prompt('What is your name?');
};
while (name === '');
To fix this error, make sure there is nothing between the loop's body and the
while keyword:
let name;
do {
name = prompt('What is your name?');
}
while (name === '');
switch statements require a body, which must be a list of statements
surrounded by { and }. It is a syntax error to omit the body of an switch
statement:
function colorToHexCode(color) {
switch (color)
}
To fix this error, write the body of the switch statement:
function colorToHexCode(color) {
switch (color) {
case 'red': return '#ff0000';
case 'green': return '#00ff00';
case 'blue': return '#0000ff';
}
}
There are three kinds of for loops: C-style for loops (;), for-in
loops, and for-of loops. It is a syntax error to write a for-in loop
with a ;:
for (let i in 0; i < 100; ++i) {
console.log(i % 15 ? i : "FizzBuzz");
}
let benchmarks = collectBenchmarks();
for (const name in benchmarks;) {
runBenchmark(name, benchmarks[name]);
}
To fix this error, remove the in keyword in the C-style for loop:
for (let i = 0; i < 100; ++i) {
console.log(i % 15 ? i : "FizzBuzz");
}
Alternatively, remove the extra ;:
let benchmarks = collectBenchmarks();
for (const name in benchmarks) {
runBenchmark(name, benchmarks[name]);
}
It is a syntax error to write the export keyword without anything following:
class SmallBenchmark extends Benchmark {}
export {SmallBenchmark};
class BigBenchmark extends Benchmark {}
export
for (let benchmark of [new SmallBenchmark(),
new BigBenchmark()]) {
registerBenchmark(benchmark);
}
To fix this error, complete the export statement:
class SmallBenchmark extends Benchmark {}
export {SmallBenchmark};
class BigBenchmark extends Benchmark {}
export {BigBenchmark};
for (let benchmark of [new SmallBenchmark(),
new BigBenchmark()]) {
registerBenchmark(benchmark);
}
Variables can be declared using a keyword such as const, let, or var. It
is a syntax error write anything except a variable name or a destructuring
pattern in a const, let, or var declaration:
let sawFizzBuzz,
100..toRange().forEach(i => {
if (i % 15) {
console.log(i);
} else {
console.log("FizzBuzz");
sawFizzBuzz = true;
}
});
let while (!done) {
doMoreWork();
}
To fix this error, replace , with ;:
let sawFizzBuzz;
100..toRange().forEach(i => {
if (i % 15) {
console.log(i);
} else {
console.log("FizzBuzz");
sawFizzBuzz = true;
}
});
Alternatively, remove the extra const, let, or var keyword:
switch statements can contain a default label. It is a syntax error to write
a default label outside a switch statement:
function colorToHexCode(color) {
switch (color) {
case 'red': return '#ff0000';
case 'green': return '#00ff00';
case 'blue': return '#0000ff';
}
default:
throw new Error(`unknown color ${color}`);
}
To fix this error, move the default label into a switch statement:
function colorToHexCode(color) {
switch (color) {
case 'red': return '#ff0000';
case 'green': return '#00ff00';
case 'blue': return '#0000ff';
default:
throw new Error(`unknown color ${color}`);
}
}
catch clauses in try statements require a body, which must be a list of
statements surrounded by { and }. It is a syntax error to omit the body of a
catch clause:
const fs = require("fs");
async function readConfig(configFilePath) {
try {
let data = await fs.promises.readFile(
configFilePath,
"utf-8",
);
return parseConfig(data);
} catch (error)
}
To fix this error, write the body of the catch statement, including { and
}:
const fs = require("fs");
async function readConfig(configFilePath) {
try {
let data = await fs.promises.readFile(
configFilePath,
"utf-8",
);
return parseConfig(data);
} catch (error) {
if (error.code === 'ENOENT') {
return {};
} else {
throw error;
}
}
}
finally clauses in try statements require a body, which must be a list of
statements surrounded by { and }. It is a syntax error to omit the body of a
finally clause:
let recursionDepth = 0;
function recursionExample() {
if (recursionDepth > 100) {
throw new Error("too much recursion!");
}
recursionDepth += 1;
try {
recursionExample();
} finally
}
To fix this error, write the body of the finally statement, including { and
}:
let recursionDepth = 0;
function recursionExample() {
if (recursionDepth > 100) {
throw new Error("too much recursion!");
}
recursionDepth += 1;
try {
recursionExample();
} finally {
recursionDepth -= 1;
}
}
A try statement has a list of statements followed by an optional catch block
followed by an optional finally block. It is a syntax error to omit both the
catch block and the finally block:
async function readConfig(configFilePath) {
try {
let data = await fs.promises.readFile(
configFilePath,
"utf-8",
);
return parseConfig(data);
}
}
let recursionDepth = 0;
function recursionExample() {
if (recursionDepth > 100) {
throw new Error("too much recursion!");
}
recursionDepth += 1;
try {
recursionExample();
}
}
To fix this error, remove the try keyword:
async function readConfig(configFilePath) {
let data = await fs.promises.readFile(
configFilePath,
"utf-8",
);
return parseConfig(data);
}
Alternatively, add a catch block after the try block:
async function readConfig(configFilePath) {
try {
let data = await fs.promises.readFile(
configFilePath,
"utf-8",
);
return parseConfig(data);
} catch (error) {
if (error.code === 'ENOENT') {
return {};
} else {
throw error;
}
}
}
Alternatively, add a finally block after the try block:
let recursionDepth = 0;
function recursionExample() {
if (recursionDepth > 100) {
throw new Error("too much recursion!");
}
recursionDepth += 1;
try {
recursionExample();
} finally {
recursionDepth -= 1;
}
}
A try statement can have a catch clause. The catch clause can define a
variable for the caught exception. It is a syntax error to omit the variable
name between a catch clause's parentheses:
async function downloadURLWithRetries(url) {
for (;;) {
try {
return await downloadURL(url);
} catch () {
// Loop and try again.
}
}
}
To fix this error, remove the parentheses:
async function downloadURLWithRetries(url) {
for (;;) {
try {
return await downloadURL(url);
} catch {
// Loop and try again.
}
}
}
Alternatively, write a variable name between the parentheses:
A try statement can have a catch clause. The catch clause can define a
variable for the caught exception. It is a syntax error to write a string
literal instead of a variable name between a catch clause's parentheses:
async function downloadURLWithRetries(url) {
for (;;) {
try {
return await downloadURL(url);
} catch ('ETIMEOUT') {
// Loop and try again.
}
}
}
To fix this error, replace the string literal with a variable name:
async function downloadURLWithRetries(url) {
for (;;) {
try {
return await downloadURL(url);
} catch (e) {
if (e.code === 'ETIMEOUT') {
// Loop and try again.
} else {
throw e;
}
}
}
}
When declaring a variable with const, let, or var, you can set the
variable's initial value using =. It is a syntax error to use a compound
assignment operator instead of =:
let i = 0;
while (i < 100) {
let i += 1;
console.log(i % 15 ? i : "FizzBuzz");
}
const length *= Math.sqrt(x*x + y*y + z*z);
To fix this error, remove the let keyword:
let i = 0;
while (i < 100) {
i += 1;
console.log(i % 15 ? i : "FizzBuzz");
}
Alternatively, replace the compound assignment operator with =:
A while statement has a condition which determines whether the body will
execute or not. It is an error to omit a while statement's condition:
let name = '';
while {
name = prompt('What is your name?');
}
async function downloadURLWithRetries(url) {
while {
try {
return await downloadURL(url);
} catch {
// Loop and try again.
}
}
}
To fix this error, write the condition with parentheses after the if keyword:
let name = '';
while (name === '') {
name = prompt('What is your name?');
}
Alternatively, to write an infinite loop, write for (;;) instead of while:
async function downloadURLWithRetries(url) {
for (;;) {
try {
return await downloadURL(url);
} catch {
// Loop and try again.
}
}
}
A switch statement has a list of cases, each beginning with either the case
keyword or the default keyword. It is a syntax error to omit an expression
after the case keyword:
function getText(node) {
switch (node.nodeType) {
case document.TEXT_NODE:
return node.nodeValue;
case: {
let result = "";
for (let child of node.childNodes) {
result += getText(child, document);
}
return result;
}
default:
throw new Error("Unsupported DOM node type");
}
}
function colorToHexCode(color) {
switch (color) {
case 'red': return '#ff0000';
case 'green': return '#00ff00';
case 'blue': return '#0000ff';
case:
throw new Error(`unknown color ${color}`);
}
}
To fix this error, write an expression (usually a constant) after the case
keyword:
function getText(node) {
switch (node.nodeType) {
case document.TEXT_NODE:
return node.nodeValue;
case document.ELEMENT_NODE: {
let result = "";
for (let child of node.childNodes) {
result += getText(child, document);
}
return result;
}
default:
throw new Error("Unsupported DOM node type");
}
}
Alternatively, replace the case keyword with default if the code should
execute if no other case would:
function colorToHexCode(color) {
switch (color) {
case 'red': return '#ff0000';
case 'green': return '#00ff00';
case 'blue': return '#0000ff';
default:
throw new Error(`unknown color ${color}`);
}
}
A function call requires a list of arguments surrounded by ( and ). It is a
syntax error to omit the final ) in a function call:
for (let i = 0; i < iterationCount; ++i) {
console.log("starting iteration", i, "...";
runBenchmarkIteration();
console.log("finished iteration", i);
}
To fix this error, write the closing ):
for (let i = 0; i < iterationCount; ++i) {
console.log("starting iteration", i, "...");
runBenchmarkIteration();
console.log("finished iteration", i);
}
The ? : ternary operator has three parts: the condition, the expression if
true, and the expression if false. It is a syntax error to omit the expression
if false:
for (let i = 1; i <= 100; ++i) {
console.log(i % 15 ? i);
}
document.querySelector("form input")?focus();
To fix this error, write : followed by an expression:
for (let i = 1; i <= 100; ++i) {
console.log(i % 15 ? i : "FizzBuzz");
}
Alternatively, write ?. instead of ? to access an object's property:
do-while loops, for loops, while loops, and with statements require a
statement or list of statements for the body. It is a syntax error to write a
function as the body of such a statement:
let flavors = [];
for (let flavor in config.sweets)
function getFavoriteFlavor() {
return "chocolate";
}
To fix this error, write the body of the do-while loop, for loop, while
loop, or with statement:
let flavors = [];
for (let flavor in config.sweets) {
flavors.push(flavor);
}
function getFavoriteFlavor() {
return "chocolate";
}
do-while loops, if statements, for loops, while loops, and with
statements require a statement or list of statements for the body. It is a
syntax error to write a class as the body of such a statement:
let flavors = [];
for (let flavor in config.sweets)
class SweetsBasket { /* ... */ }
To fix this error, write the body of the do-while loop, if statements,
for loop, while loop, or with statement:
let flavors = [];
for (let flavorName in config.sweets) {
flavors.push(flavorName);
}
class SweetsBasket { /* ... */ }
do-while loops, if statements, for loops, while loops, and with
statements require a statement or list of statements for the body. It is a
syntax error to declare a variable with const or let as the body of such a
statement:
let flavors = [];
for (let flavor in config.sweets)
let favoriteFlavor = random.pick(flavors);
To fix this error, write the body of the do-while loop, if statements,
for loop, while loop, or with statement:
let flavors = [];
for (let flavorName in config.sweets) {
flavors.push(flavorName);
}
let favoriteFlavor = random.pick(flavors);
A function parameter can be a variable name, an array destructuring, or an
object destructuring. It is a syntax error for a function parameter to look like
a function call or any other expression:
A legacy octal literal is a 0 digit followed by one or more octal digits (0
through 7). It is a syntax error for a legacy octal literal to contain a digit
separator (_):
Object literals can contain methods, object spreads, shorthand properties, and
key-value pairs. It is a syntax error to write a complex value (expression)
without a key in an object literal:
Classes can declare private properties with #. Object cannot have private
properties. It is a syntax error to declare a private property in an object
literal:
An arrow function has a parameter list followed by => followed by a body. It
is a syntax error to write an arrow function with a literal instead of a
parameter list:
A function parameter can be a variable name, an array destructuring, or an
object destructuring. It is a syntax error for a function parameter list to
contain a number literal:
function drop(array, count, 0) {
return array.slice(count);
}
To fix this error, make the literal a default value of a parameter:
function drop(array, count = 0) {
return array.slice(count);
}
The left-hand side of => must be a list of parameters. It is a syntax error if
the left-hand side is instead an expression (such as a property access or a
function call):
if (this.mapSize => this.capacity) {
throw new Error("too many items");
}
let fs = require("fs");
let path = process.argv[2];
fs.mkdir(path () => console.log("done"));
To fix this error, replace => with the intended operator, such as >=:
if (this.mapSize >= this.capacity) {
throw new Error("too many items");
}
Alternatively, make the left-hand side of => valid by adding an operator
(usually ,) before the parameter list:
let fs = require("fs");
let path = process.argv[2];
fs.mkdir(path, () => console.log("done"));
The await operator can be used in async functions and in modules at the top
level. It is a syntax error to use the await operator in a non-async
function:
function readConfig(configFilePath) {
let data = await fs.promises.readFile(
configFilePath,
"utf-8",
);
return parseConfig(data);
}
async function takeOverTheWorld() {
let config = readConfig(CONFIG_FILE);
if (config.prettyPlease) {
await reallyTakeOverTheWorld();
}
}
To fix this error, declare the function as async, ensuring that callers use
await too:
async function readConfig(configFilePath) {
let data = await fs.promises.readFile(
configFilePath,
"utf-8",
);
return parseConfig(data);
}
async function takeOverTheWorld() {
let config = await readConfig(CONFIG_FILE);
if (config.prettyPlease) {
await reallyTakeOverTheWorld();
}
}
An async arrow function has a parameter list following the async keyword. It
is a syntax error for the parameter list to start on line different from the
async keyword:
In a quick-lint-js configuration file, a entry in "globals" can have a
descriptor object. A descriptor's "shadowable" property must be either true,
false, or omitted.
{
"globals": {
"gsap": {
"shadowable": 0
}
}
}
To fix this error, make the "shadowable" property true or false:
In a quick-lint-js configuration file, a entry in "globals" can have a
descriptor object. A descriptor's "writable" property must be either true,
false, or omitted.
{
"globals": {
"gsap": {
"writable": 0
}
}
}
To fix this error, make the "writable" property true or false:
In a quick-lint-js configuration file, "globals" must be an object or
omitted. It is an error if "globals" is an array, a boolean, a number, a
string, or null:
In a quick-lint-js configuration file, "global-groups" must be an array of
strings, a boolean, or omitted. It is an error if "global-groups" is a
boolean, a number, an object, a string, or null:
In a quick-lint-js configuration file, items in the "global-groups" array
must be strings. It is an error if an item is an array, a boolean, a number, an
object, or null:
In a quick-lint-js configuration file, each entry in "globals"
must be a boolean or a descriptor object. It is an error if a "globals" item
is an array, a number, a string, or null:
{
"globals": {
"gsap": "true"
}
}
To fix this error, make the "globals" entry true or false:
There are three kinds of for loops: C-style for loops (;), for-in
loops, and for-of loops. It is a syntax error to write a for-in or
for-of loop which declares a variable with const or let and initializes
the variable:
function firstItem(collection) {
for (const item = null of collection) {
break;
}
return item;
}
To fix this error, declare the variable outside the for-in or for-of
loop with let:
function firstItem(collection) {
let item = null;
for (item of collection) {
break;
}
return item;
}
import statements load things from other files. When importing, you can pick a
different name for the imported data using the as keyword: It is a syntax
error to write anything except a variable name after as:
import {createElement as "CE"} from "react";
function Hello() {
return CE('h1', null, 'Hello, world!');
}
import {first as "first-element"} from "./utilitylib.mjs";
To fix this error, write a variable name after as:
import {createElement as CE} from "react";
function Hello() {
return CE('h1', null, 'Hello, world!');
}
Alternatively, swap the left and right side of as:
import {"first-element" as first} from "./utilitylib.mjs";
A return statement can have an optional expression. If the expression is
omitted, undefined is returned.
If a return statement has an expression, the expression must start on the same
line as the return keyword. If an expression starts on the next line, the
return statement behaves as if no expression was given, so the returned
value is undefined and the next line is skipped:
function getWebsiteBaseURL() {
return
'https://quick-lint-js.com/';
}
// TypeError: URL constructor: undefined is not a valid URL.
console.log(getWebsiteBaseURL().hostname);
To fix this error, put the returned value on the same line as the return
keyword:
function getWebsiteBaseURL() {
return 'https://quick-lint-js.com/';
}
// "quick-lint-js.com"
console.log(getWebsiteBaseURL().hostname);
A function parameter can be a variable name, an array destructuring, or an
object destructuring. It is a syntax error for a parameter name to be in
parentheses with a comma:
JSX attribute values can be strings. These strings need to be closed with either
" or ' (whichever was used to start the string). It is a syntax error to
omit " or ':
function NavLink({href, children}) {
return <li><a href={href} className="nav-link>{children}</a></li>;
}
To fix this error, end the string by writing the matching " or ':
function NavLink({href, children}) {
return <li><a href={href} className="nav-link">{children}</a></li>;
}
It is a ReferenceError to assign to variables imported from another module:
import { config } from "./default-config.js";
function updateConfig(newConfig) {
config = newConfig;
}
function dumpConfig() {
console.log(config);
}
To fix this error, create a new variable with let and use it instead.
import { config as defaultConfig } from "./default-config.js";
let config = defaultConfig;
function updateConfig(newConfig) {
config = newConfig;
}
function dumpConfig() {
console.log(config);
}
In JSX, each opening tag must either be self-closing or have a corresponding
closing tag. It is a syntax error for the closing tag to have a different tag
name than the opening tag:
function Section({children}) {
return <div className="section">{children}</DIV>;
}
function SignUpButton() {
return <div className="button">
<Link to="/signup">Join <strong>now</Link></strong>
</div>;
}
To fix this error, make the ending tag and the opening tag use the same name:
function Section({children}) {
return <div className="section">{children}</div>;
}
Alternatively, swap the incorrectly-nested closing tags:
In an if statement or a loop, it is likely a mistake to use = to compare a
variable with a constant:
let headingLinks = [];
for (let el of document.querySelectorAll("a")) {
if (el.parentNode.tag = "H1") {
headingLinks.push(el);
}
}
for (let x, i = 0; x = null; ++i) {
if (xs[i] < 0) {
break;
} else if (xs[i] > 0) {
x = xs[i];
}
out.push(x);
}
To fix this error, write === or == instead of = to compare for equality:
let headingLinks = [];
for (let el of document.querySelectorAll("a")) {
if (el.parentNode.tag === "H1") {
headingLinks.push(el);
}
}
Alternatively, if assignment was intended, write parentheses around the
assignment to suppress the warning:
for (let x, i = 0; (x = null); ++i) {
if (xs[i] < 0) {
break;
} else if (xs[i] > 0) {
x = xs[i];
}
out.push(x);
}
In English, we might say “if the selection is ‘agree’ or ‘strongly agree’,
return a rating of 1”. If this English phrase is translated naïvely into
JavaScript, the code will behave as if every selection has a rating of 1:
function getRating(radioElement) {
let selection = radioElement.value;
if (selection === "agree" || "strongly agree") {
return 1;
} else if (selection === "disagree") {
return 0;
} else if (selection === "strongly disagree") {
return -1;
}
}
This happens because if (selection === "agree" || "strongly agree") is
interpreted as if ((selection === "agree") || "strongly agree"), i.e. “if
selection is ‘agree’, or if ‘strongly agree’ is truthy, then …”. Because the
string "strongly agree" is not empty, it is truthy, and the condition is
always true.
To fix this error, write the == or === comparison on both sides of ||:
function getRating(radioElement) {
let selection = radioElement.value;
if (selection === "agree" ||
selection === "strongly agree") {
return 1;
} else if (selection === "disagree") {
return 0;
} else if (selection === "strongly disagree") {
return -1;
}
}
In HTML, attributes are case-insensitive; onclick is the same as onClick and
ONCLICK. In React, attributes are case-sensitive. It is a mistake for an event
attribute (starting with on) to be all lower-case:
In HTML, attributes are case-insensitive; colspan is the same as colSpan and
COLSPAN. In React, attributes are case-sensitive. It is a mistake for an
attribute for a built-in element to have the wrong capitalization:
A break statement exits a do-while loop, for loop, while loop, or
switch statement. It is a syntax error for a break statement to appear
outside these loops or a switch statement:
friends.forEach((friend) => {
hand.giveHighFive(friend);
if (hand.isTired) {
break;
}
});
To fix this error, write a for-of loop instead of using the forEach
method:
for (const friend of friends) {
hand.giveHighFive(friend);
if (hand.isTired) {
break;
}
}
A continue statement exit the current iteration of a do-while loop, for
loop, or while loop. It is a syntax error for a
continue statement to appear outside these loops:
benchmarks.forEach(benchmark => {
if (benchmark.shouldSkip) continue;
benchmark.warmUp();
if (benchmark.varianceTooHigh) continue;
benchmark.run();
});
To fix this error, write a for-of loop instead of using the forEach method:
for (let benchmark of benchmarks) {
if (benchmark.shouldSkip) continue;
benchmark.warmUp();
if (benchmark.varianceTooHigh) continue;
benchmark.run();
}
Alternatively, use return to exit the current iteration's function:
benchmarks.forEach(benchmark => {
if (benchmark.shouldSkip) return;
benchmark.warmUp();
if (benchmark.varianceTooHigh) return;
benchmark.run();
});
Alternatively, write an if statement to skip the undesired code:
benchmarks.forEach(benchmark => {
if (!benchmark.shouldSkip) {
benchmark.warmUp();
if (!benchmark.varianceTooHigh) {
benchmark.run();
}
}
});
JavaScript code can contain nested functions, arrays, objects, classes, etc.
quick-lint-js only supports nesting up to a limit. Most code shouldn't hit this
limit. If you do hit this limit, refactor your code to reduce nesting.
Identifiers, string literals, and template literals can contain Unicode escape
sequences starting with \u. It is a syntax error for a Unicode escape sequence
to refer to a character which is beyond the range of valid Unicode code points
(U+0000 to U+10FFFF):
class ChirpSound {}
let bird\u{360000} = new ChirpSound();
let x = "hello\u{abcdef}";
To fix this error, make sure that the escaped code point is
between U+0000 and U+10FFFF inclusive.
class ChirpSound {}
let bird\u{3600} = new ChirpSound();
let x = "hello\u{abcde}";
Classes and object literals have a similar syntax for declaring methods. Object
literal entries are separated by commas, but class entries are not separated by
commas. It is a syntax error to use a comma to separate class entries:
Block comments start with /* and end with */. It is a syntax error for a
block comment to end but not start:
//
// this code is really complicated.
// some might say too complicated.
*/
function yes() {
return true;
}
/*
console.log("[debug] state:");
debugPrint(state, /*depth=*/3);
*/
let heightInFeet = heightInCM */ 3.28;
To fix this error, remove the */:
//
// this code is really complicated.
// some might say too complicated.
function yes() {
return true;
}
Alternatively, use // or if (false) to avoid nesting block comments:
if (false) {
console.log("[debug] state:");
debugPrint(state, /*depth=*/3);
}
Alternatively, write an expression between * and /: