TypeScript error

TS2345: An argument does not match the parameter's type

  • Error TS2345
  • Tested with TypeScript 5.9

error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. is reported at a call when an argument does not fit the type the function's @param tag declares. It is the call-site twin of TS2322: same comparison, reported on the argument.

In JavaScript code two cases account for most of these errors: text from the DOM (an input's value is always a string) passed where a number is expected, and an optional property passed on as if it were always set. The second only appears with strictNullChecks, which strict turns on.

At a glance

CodeTS2345
MessageArgument of type '{0}' is not assignable to parameter of type '{1}'.
TypeScript's categoryerror
Listed underTypes do not match
Turned on by No option: every checked file reports it
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} and {1} are 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(9,27): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. price.js(9,27): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. price.js(9,27): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'. checked 21 October 2026
/** @param {number} cents */
export function formatPrice(cents) {
  return `$${(cents / 100).toFixed(2)}`;
}

const field = document.querySelector("input");
if (field) {
  console.log(formatPrice(field.value));error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
}
Passing a form field's text where a number is expected.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}
order.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: order.js(11,34): error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'. Type 'undefined' is not assignable to type 'number'. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. order.js(11,34): error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'. Type 'undefined' is not assignable to type 'number'. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. order.js(11,34): error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'. Type 'undefined' is not assignable to type 'number'. checked 21 October 2026
/** @typedef {{ id: string, discountCents?: number }} Order */

/** @param {number} cents */
export function formatPrice(cents) {
  return `$${(cents / 100).toFixed(2)}`;
}

/** @param {Order} order */
export function discountLabel(order) {
  return `You save ${formatPrice(order.discountCents)}`;error TS2345: Argument of type 'number | undefined' is not assignable to parameter of type 'number'.
  Type 'undefined' is not assignable to type 'number'.
}
Passing a value that may be undefined.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

What causes it

  • The function's @param tag declares a type and the argument has another one.
  • The argument may be undefined or null (an optional property, the result of find, a DOM lookup) and the parameter's type does not include it. The message then ends with Type 'undefined' is not assignable to type 'number'.

How to fix it

Convert or check the argument at the call

Turn form text into a number with Number(field.value), or read field.valueAsNumber on a number input. For a value that may be missing, check it first; after if (order.discountCents === undefined) return ... the checker knows the property is a number on the next line.

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
/** @typedef {{ id: string, discountCents?: number }} Order */

/** @param {number} cents */
export function formatPrice(cents) {
  return `$${(cents / 100).toFixed(2)}`;
}

const field = document.querySelector("input");
if (field) {
  console.log(formatPrice(Number(field.value)));
  console.log(formatPrice(field.valueAsNumber));
}

/** @param {Order} order */
export function discountLabel(order) {
  if (order.discountCents === undefined) return "";
  return `You save ${formatPrice(order.discountCents)}`;
}
Converting the text, and checking for undefined first.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

Or let the function accept more

If the function can handle the other type, say so in its JSDoc: @param {number | undefined} cents, or an optional parameter @param {number} [cents]. Then handle that case inside the function, where it is written once instead of at every call.

Arguments that are functions

When the argument is a callback, the message compares function types and the indented lines say which parameter or return type differs. Fix the callback's @param tags, or drop them and let the parameter's type supply them: a function passed directly gets its parameter types from the context.

Gotchas

  • An object literal argument with a property the parameter's type does not have is reported as TS2353, not TS2345.
  • If the function has several call signatures (overloads, or a built-in such as new Date()), a mismatch is reported as TS2769 and lists each signature.
  • parseInt(field.value) also converts text, but an empty field gives NaN from parseInt and 0 from Number; the checker only sees number either way.

Questions

The value is a number when the code runs. Why does tsc say string?

The checker goes by declared types, not by values at run time. HTMLInputElement.value is declared as string in TypeScript's DOM types even for <input type="number">; valueAsNumber is the property declared as number.

Sources

Last reviewed 20 October 2026.