JavaScript’s number type uses IEEE 754 double-precision floating-point arithmetic. Many decimal fractions, and division results whose
exact value is non-integer cannot be represented exactly in binary, so calculations that look simple may produce slightly different values.
0.1 + 0.2 === 0.3; // false
As a result, exact equality and inequality checks on floating-point-sensitive values can produce unexpected results. For JavaScript and TypeScript,
this rule is intentionally conservative: it targets exact comparisons on values that are statically floating-point-sensitive, such as decimal
arithmetic or floating-point constants, not every equality check on number.
When the compared values are expected to be close rather than exactly identical, use a tolerance-based comparison instead of an exact equality or
inequality check. When the arithmetic is around the magnitude of 1, Number.EPSILON is often a reasonable starting threshold,
following the testing-equality guidance in the MDN documentation. For larger magnitudes or lower-precision inputs, a larger fixed tolerance may be
needed. Choose one that fits the expected precision of the values being compared.
const total = 0.1 + 0.2;
const average = 0.9 + 0.2;
if (total === 0.3) { // Noncompliant: exact comparison on decimal arithmetic
publish(total);
}
const status = total === 0.3 ? "done" : "retry"; // Noncompliant: exact comparison inside a ternary
if (average <= 1.1 && average >= 1.1) { // Noncompliant: equivalent to an exact "===" test
publish(average);
}
if (average < 1.1 || average > 1.1) { // Noncompliant: equivalent to an exact "!==" test
publish(average);
}
if (getRatio() !== 10 / 3) { // Noncompliant: exact comparison against fraction-producing arithmetic
publish(getRatio());
}
const total = 0.1 + 0.2;
const average = 0.9 + 0.2;
if (Math.abs(total - 0.3) < Number.EPSILON) {
publish(total);
}
const status = Math.abs(total - 0.3) < Number.EPSILON ? "done" : "retry";
if (Math.abs(average - 1.1) < Number.EPSILON) {
publish(average);
}
if (Math.abs(average - 1.1) >= Number.EPSILON) {
publish(average);
}
if (Math.abs(getRatio() - 10 / 3) >= 1e-12) {
publish(getRatio());
}
In frameworks with Jest-style expect matchers, use an approximate matcher instead of an exact matcher when the expected value is
floating-point-sensitive.
import { expect, test } from "vitest";
test("computes a total", () => {
expect(0.1 + 0.2).toBe(0.3);
});
import { expect, test } from "vitest";
test("computes a total", () => {
expect(0.1 + 0.2).toBeCloseTo(0.3);
});
With Node.js assert, replace exact equality assertions on floating-point-sensitive values with a tolerance-based predicate or a helper
that performs an approximate comparison.
import assert from "node:assert/strict"; assert.strictEqual(0.1 + 0.2, 0.3);
import assert from "node:assert/strict";
function almostEqual(actual, expected, tolerance = Number.EPSILON) {
return Math.abs(actual - expected) < tolerance;
}
assert.ok(almostEqual(0.1 + 0.2, 0.3));
With Chai, replace exact equality assertions on floating-point-sensitive values with approximate assertions such as closeTo or
approximately. The same guidance applies to Cypress, which exposes Chai assertions through expect and
.should().
import { expect } from "chai";
expect(0.1 + 0.2).to.equal(0.3);
import { expect } from "chai";
expect(0.1 + 0.2).to.be.closeTo(0.3, Number.EPSILON);
Number.EPSILON
- Testing equalityexpectexpectTest runnershould