Skip to content

Fix false implicit-any errors in annotated nested bindings - #64440

Draft
Ryan Cavanaugh (RyanCavanaugh) with Copilot wants to merge 9 commits into
mainfrom
copilot/fix-ts7031-nested-object-binding
Draft

Ryan Cavanaugh (RyanCavanaugh) with Copilot wants to merge 9 commits into
mainfrom
copilot/fix-ts7031-nested-object-binding

Conversation

Copilot AI commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Nested object bindings with = {} incorrectly reported TS7031 despite an enclosing parameter annotation supplying the binding element type.

function f({ inner: { b } = {} }: Outer) {
    return b; // number | undefined, not any
}
  • Cause

    • Object-literal padding reported implicit-any for every missing binding element, including elements rooted in annotated declarations.
  • Change

    • Report implicit-any during padding only when the root declaration lacks a type annotation.
    • Add regression coverage for nested bindings with and without sibling defaults.

Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix TS7031 false positive for nested object binding pattern Fix false implicit-any errors in annotated nested bindings Sep 24, 2026
@RyanCavanaugh

Copy link
Copy Markdown
Member

Copilot mcfly this and also explain why this is a correct fix

Copilot AI and others added 6 commits September 25, 2026 15:51
This reverts commit 2970fae.

Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
Co-authored-by: RyanCavanaugh <6685088+RyanCavanaugh@users.noreply.github.com>
@trevorade

Copy link
Copy Markdown
Contributor

I had my agent check this fix. Here's what it has to say about it.


Tried this against the cases we hit in our codebase. It clears all of them, and it also gets the types right in a nested callback case (deepCb(({inner: {b} = {}}) => b) gives b: string | undefined, same as 6.0).

Two cases still differ from 6.0.3:

// 1. Contextual type is `any`: TS7031 on `a` (6.0.3: clean)
declare function anyCb(cb: (x: any) => void): void;
anyCb(({a} = {}) => { void a; });

// 2. One element missing from the contextual type: TS7031 on `q` too (6.0.3: only TS2339 on `extra`)
interface Opts { q?: string; }
declare function onTab(cb: (id: string, opts?: Opts) => void): void;
onTab((id, {q, extra} = {}) => { void [id, q, extra]; });

(2) happens because hasContextualTypeForObjectBindingPattern is all-or-nothing, so one element without a contextual property type re-pads the whole pattern.

Also, the .types/.symbols baselines are missing the contextual(...) line from the test file, so TestLocal/objectBindingPatternDefaultAnnotated.ts fails as-is. No other baselines change.

Sawyer Hood (SawyerHood) added a commit to get-bb/bb that referenced this pull request Oct 20, 2026
## Human comments

## What was wrong

Typechecking ran on TypeScript 7.0.2 (`typescript-7` →
`npm:typescript@^7.0.2`).
[tsrs](https://blog.cloudflare.com/typescript-rust-port), the Rust port
of the TypeScript 7 compiler, is roughly twice as fast and uses half the
memory on bb (numbers below). This PR moves bb's typechecking to it.

tsrs 0.18.0 is a faithful port of TypeScript `7.1.0-dev.20260930.4` and
prints the same diagnostics. Moving to it therefore also moves bb onto a
7.1 nightly, which brings two upstream regressions. tsrs also has no
Windows binary yet:

1. **TS5115 on zod's `z.json()`** ("Instantiations of the following
types appear infinitely circular: 'IsOptionalIn', '$ZodTypeInternals',
'$InferZodRecordInput'"). Reported as microsoft/TypeScript#64605. The
first nightly that fails is `7.1.0-dev.20260929.1`, after
microsoft/TypeScript#64372.
2. **TS7031 on a contextually typed destructured parameter with `=
{}`.** Reported as microsoft/TypeScript#64431, with fixes proposed in
microsoft/TypeScript#64440 and microsoft/TypeScript#64671. The first
nightly that fails is `7.1.0-dev.20260923.1`.
3. **No `win32-x64` package through 0.18.0.** tsrs's `npm/README.md`
says its release workflow now builds one. Intel Macs remain unsupported.

## What changed

- **tsrs replaces TypeScript 7 for typechecking.** Every `package.json`
that listed `typescript-7` now lists `tsrs` pinned to
`0.18.0-ts7.1.0-dev.20260929` (exact pin because the releases are
experimental), and every `typecheck` script runs `tsrs --noEmit`.
`typescript` (the `@typescript/typescript6` JS API) stays for tooling
that imports it.
- **Workaround for regression 1.** Core code uses
`jsonValueSchema`/`jsonObjectSchema` from `@bb/domain` instead of
`z.json()`: `apps/desktop` (CDP + capture, plus two tests) and
`packages/desktop-contract`. Forkable plugins can't import `@bb/domain`,
so account-pool, bb-account, connect, mcp and workflows each define the
same `z.lazy` schema, typed with the SDK's `JsonValue`. That schema has
the same structure as zod's `z.json()`, so runtime validation is
unchanged. The only remaining `z.json()` calls are in two tests that
don't trigger the error.
- **Workaround for regression 2.** The abort-signal mock in
`system-config-atoms.local-access.test.ts` annotates its parameter.
- **Windows.** The `windows-foundation` job now runs `lint test` without
`typecheck`. The Windows typecheck steps in `build-desktop.yml` and the
`nightly-desktop-windows` job are removed.
`plugin-authoring-doc-examples.test.ts` now launches tsrs and skips on
win32. Types don't depend on the OS, and the Linux `static-checks` job
still typechecks every package. These can come back once tsrs publishes
`win32-x64`.
- Left alone: the plugin scaffold's `typescript` dependency for user
plugins, and the bb-app tarball smoke test's `npx typescript` consumer
check. Both stand in for what plugin authors and SDK users run.

## How you verified

- `pnpm exec turbo run typecheck --force --continue` on tsrs: 105/105
pass. Before the workarounds, 7 failed, with 16 TS5115 errors and 1
TS7031.
- Every changed package also passes `tsc --noEmit` on TypeScript 7.0.2.
- Both regressions reproduce on tsc `7.1.0-dev.20260930.4` and today's
`7.1.0-dev.20261020.3`, and pass on 7.0.2. I found the first failing
nightly for each by trying successive builds.
- `turbo run lint test` for `@bb/desktop`, `@bb/desktop-contract`,
account-pool, bb-account, connect, bb--mcp and workflows: 16/16 pass.
The doc-examples test passes with tsrs, and the system-config atoms test
passes (12/12).
- Speed, same machine, warm, `--noEmit`, best of two runs:

  | package | tsc (TS 7.0.2) | tsrs |
  |---|---|---|
  | `apps/server` | 11.3s, 3.3 GB | 5.5s, 1.6 GB |
  | `apps/app` | 11.4s, 3.4 GB | 6.4s, 1.7 GB |

- `pnpm install --frozen-lockfile` is clean, and `oxfmt --check` passes.

> AGENT GENERATED

---------

Co-authored-by: Sawyer <kirbyhood@gmail.com>

This branch has not been deployed

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

Labels

For Uncommitted Bug PR for untriaged, rejected, closed or missing bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

TS7031 false positive for nested object binding pattern with = {} default in an annotated parameter (regression from #64043)

3 participants