TypeScript error

TS7031: A destructured parameter without a type

  • Error TS7031
  • Reported with noImplicitAny
  • Reported with strict
  • Tested with TypeScript 5.9

error TS7031: Binding element 'name' implicitly has an 'any' type. is the destructuring form of TS7006: a parameter written as { name, email } (or [first, second]) has no type, so every name pulled out of it is reported once.

JSDoc has no place to put a type next to each name, so the tag describes the whole object. The tag's name is yours to pick, because the parameter itself has none.

At a glance

CodeTS7031
MessageBinding element '{0}' implicitly has an '{1}' type.
TypeScript's categoryerror
Listed underImplicit any
Turned on by noImplicitAny, 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} and {1} are filled in by tsc for each error.

What it looks like

user.js Error confirmed 5.9.3 TypeScript 5.9.3, run 21 October 2026: user.js(2,28): error TS7031: Binding element 'name' implicitly has an 'any' type. user.js(2,34): error TS7031: Binding element 'email' implicitly has an 'any' type. 6.0.3 TypeScript 6.0.3, run 21 October 2026: the same as 5.9.3. user.js(2,28): error TS7031: Binding element 'name' implicitly has an 'any' type. user.js(2,34): error TS7031: Binding element 'email' implicitly has an 'any' type. 7.0.2 TypeScript 7.0.2, run 21 October 2026: the same as 5.9.3. user.js(2,28): error TS7031: Binding element 'name' implicitly has an 'any' type. user.js(2,34): error TS7031: Binding element 'email' implicitly has an 'any' type. checked 21 October 2026
export function userCard({ name, email }) {error TS7031: Binding element 'name' implicitly has an 'any' type.error TS7031: Binding element 'email' implicitly has an 'any' type.
  return `${name} <${email}>`;
}
Destructured parameters without a type.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

What causes it

  • A parameter is a destructuring pattern and there is no @param tag for it, no default value with a type, and no context (a typed callback) to supply one.
  • noImplicitAny is on (part of strict).

How to fix it

Describe the object in one @param tag

@param {{ name: string, email: string }} user types both names. For a longer list, the nested form reads better: @param {object} options followed by @param {string} options.name and @param {boolean} [options.compact], with brackets for optional ones. A @typedef works too, when other functions take the same object.

user.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 {{ name: string, email: string }} user
 */
export function userCard({ name, email }) {
  return `${name} <${email}>`;
}

/**
 * @param {object} options
 * @param {string} options.name
 * @param {boolean} [options.compact]
 */
export function badge({ name, compact = false }) {
  return compact ? name.slice(0, 1) : name;
}
One @param tag for the whole object.
jsconfig.json for this example
{
  "compilerOptions": {
    "checkJs": true,
    "noEmit": true,
    "strict": true,
    "target": "es2022",
    "module": "nodenext",
    "types": []
  },
  "include": ["*.js"]
}

Gotchas

  • A default in the pattern (compact = false) types that one name, but the others still need the tag.
  • The names in nested @param tags must match the destructured names. A misspelled one (options.nam) describes a property the pattern does not read, so the destructured name is reported as TS2339.

Sources

Last reviewed 20 October 2026.