TypeScript error

TS2454: A variable is read before it is set

  • Error TS2454
  • Reported with strictNullChecks
  • Reported with strict
  • Tested with TypeScript 5.9

error TS2454: Variable 'discount' is used before being assigned. is reported when a variable declared with a type but no initial value is read on a path where nothing has assigned it yet. JavaScript would read undefined, which the declared type does not allow.

In a .js file the error needs a type on the variable (/** @type {number} */ let discount;). Without one, the variable's type grows to include undefined and the same read is reported as TS18048 instead.

At a glance

CodeTS2454
MessageVariable '{0}' is used before being assigned.
TypeScript's categoryerror
Listed underNull, undefined and unknown
Turned on by strictNullChecks, strict
In .js files Reported when the file is checked: checkJs in jsconfig.json, or // @ts-check at the top of the file

The message is TypeScript's own text from its diagnostic messages file (Apache-2.0); {0} is filled in by tsc for each error.

What it looks like

price.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: price.js(10,23): error TS2454: Variable 'discount' is used before being assigned. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. price.js(10,23): error TS2454: Variable 'discount' is used before being assigned. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. price.js(10,23): error TS2454: Variable 'discount' is used before being assigned. checked 21 October 2026
/**
 * @param {number} price
 * @param {boolean} member
 */
export function memberPrice(price, member) {
  /** @type {number} */
  let discount;
  if (member) discount = 0.1;
  return price * (1 - discount);error TS2454: Variable 'discount' is used before being assigned.
}
A typed variable read on a path where it was never set.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

What causes it

  • The variable is assigned in some branches (if (member) discount = 0.1;) but not all, and read after them.
  • strictNullChecks (part of strict) is on.

How to fix it

Start with a value, or assign on every branch

let discount = 0; covers the missing branch and lets the checker infer number, so the @type tag is no longer needed. When the value is chosen by a condition, a const with a conditional expression is shorter still.

price.js TypeScript 5.9.3 TypeScript 5.9.3, run 21 October 2026: No errors. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. No errors. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. No errors. checked 21 October 2026
/**
 * @param {number} price
 * @param {boolean} member
 */
export function memberPrice(price, member) {
  let discount = 0;
  if (member) discount = 0.1;
  return price * (1 - discount);
}

/**
 * @param {number} price
 * @param {boolean} member
 */
export function memberPriceTernary(price, member) {
  const discount = member ? 0.1 : 0;
  return price * (1 - discount);
}
Give the variable a starting value.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

Gotchas

  • A variable assigned inside a callback (items.forEach(() => { total = ... })) is not counted as assigned when the code after the call runs, because the checker cannot know the callback ran.
  • Using a let or const before its declaration line is a different error (TS2448, used before its declaration); JavaScript throws a ReferenceError for it at run time too.

Sources

Last reviewed 20 October 2026.