Skip to content

7.1: destructured parameter with a = {} default loses its contextual type (TS7031) #64974

Open

Description

🔎 Search Terms

TS7031, binding element implicitly has an any type, destructuring parameter default, contextual type, 7.1 regression

🕗 Version & Regression Information

  • This changed between versions 7.0.2 and 7.1.0-beta
  • Still present in 7.1.0-dev.20261026.1
  • 6.0.3 and 7.0.2 report no errors

⏯ Playground Link

No response

💻 Code

// tsconfig: { "compilerOptions": { "strict": true, "noEmit": true, "skipLibCheck": true, "types": [] } }
type Fn = (input?: { channel?: string; minutes?: number }) => number;
export const f: Fn = ({ channel, minutes } = {}) => (channel ? 1 : 0) + (minutes ?? 0);

The error needs all three of: a destructuring pattern, an = {} initializer, and a contextually typed optional parameter. Each of these alone still checks cleanly on 7.1:

type F2 = (input: { channel?: string; minutes?: number }) => number;
export const f2: F2 = ({ channel, minutes }) => (channel ? 1 : 0) + (minutes ?? 0); // no initializer: OK

type G = (input?: { channel?: string }) => number;
export const g: G = (input = {}) => (input.channel ? 1 : 0); // identifier, not a pattern: OK

🙁 Actual behavior

a.ts(2,25): error TS7031: Binding element 'channel' implicitly has an 'any' type.
a.ts(2,34): error TS7031: Binding element 'minutes' implicitly has an 'any' type.

🙂 Expected behavior

No errors: channel and minutes take their types (string | undefined, number | undefined) from the contextual parameter type, as on 6.0.3 and 7.0.2.

Additional information about the issue

Found while trialling 7.1.0-beta on a large monorepo; it fires in test helpers and callbacks typed through an alias (({ a, b } = {}) => … assigned to a function type with an optional object parameter).

Activity

  1. jltrv commented on Oct 27, 2026

    @jltrv

    Two more variants of the same regression, both fine on 7.0.2 and both still failing on 7.1.0-dev.20261027.1.

    1. Explicitly annotated parameter, no contextual typing. A pattern nested under a property with a = {} default loses the declared type:

    type Options = { inner?: { x?: string; y?: string } };
    
    export function f({ inner: { x, y } = {} }: Options) {
      return `${x}${y}`;
    }
    
    // Top-level pattern with an annotation and a `= {}` default: no error on any version
    export function g({ x, y }: { x?: string; y?: string } = {}) {
      return `${x}${y}`;
    }

    2. Non-empty object literal default. Only the properties missing from the initializer are flagged:

    type Props = { a: boolean; b?: string };
    type Fn = (props: Props) => string;
    
    export const h: Fn = ({ a, b } = { a: false }) => `${a}${b}`;

    tsconfig.json: { "compilerOptions": { "strict": true, "target": "es2022", "module": "nodenext", "noEmit": true } }

    Version Result
    6.0.2, 7.0.2 no errors
    7.1.0-beta, 7.1.0-dev.20261027.1 error TS7031: Binding element 'x' implicitly has an 'any' type. and the same for y (1), and for b (2)

    So it looks like 7.1 types a binding element missing from an object-literal initializer as implicit any instead of taking the type from the declared or contextual parameter type. An annotation on the parameter itself (g) is still honoured.

    For scale: in our codebase this accounts for all 65 new errors between 7.0.2 and 7.1.0-beta, across 23 files. They're a mix of these two forms, the contextually typed callbacks from the original report, and array.map(({ a, b } = {}) => …) callbacks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions