Skip to content
This repository was archived by the owner on Sep 1, 2026. It is now read-only.

Retain uninitialized binding patterns for variable declarations in declaration emit - #4775

Merged
Wesley Wigham (weswigham) merged 4 commits into
microsoft:mainfrom
weswigham:type-nodes-for-binding-patterns
Jul 29, 2026
Merged

Wesley Wigham (weswigham) merged 4 commits into
microsoft:mainfrom
weswigham:type-nodes-for-binding-patterns

Conversation

@weswigham

@weswigham Wesley Wigham (weswigham) commented Jul 28, 2026 •

Copy link
Copy Markdown
Member

Fixes #4525

As a side-effect, this makes exported binding patterns (potentially) isolatedDeclarations-emittable, since we can lookup their local type node/assertion/inference result the same as any other variable declaration.

Honestly, we've supported binding patterns in declaration files for... as long as I can remember, at least (and we've emitted them in parameter positions for many many major releases at this point), so I don't think there's really any harm in this - unless you'd get mad that when you write export const [,...rest] = [first(), ...others()] we now expose the type of first() in the declaration file even though it's not actually an accessible part of the exported shape. Still - that's probably worthwhile in exchange for making binding patterns isolatedDeclarations-emittable.

t = b.ch.instantiateType(b.ch.getWriteTypeOfSymbol(symbol), b.ctx.mapper)
} else if symbol != nil && (symbol.Flags&(ast.SymbolFlagsTypeLiteral|ast.SymbolFlagsSignature) == 0) {
t = b.ch.instantiateType(b.ch.getWidenedLiteralType(b.ch.getTypeOfSymbol(symbol)), b.ctx.mapper)
if symbol == nil {

@weswigham Wesley Wigham (weswigham) Jul 28, 2026 •

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The "interesting" part implementation-wise is that variable declarations hosting binding patterns do have an overall type (ofc they do), but don't have a symbol bound to them (only the individual names in the binding pattern do). Somehow, this is the first time we've needed to serialize such symbol-less declarations, so I had to adjust the pipeline to actually handle nil symbols.

(Compare with parameters where even the nameless binding pattern parameters get a bound symbol that refers to them, since that's how the argument type is looked up externally.)

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Preserves variable binding patterns in declaration emit and updates type lookup to support symbol-less declarations.

Changes:

  • Emits destructuring patterns rather than flattened declarations.
  • Adds regression coverage and updates affected baselines.
  • Handles symbol-less declaration type resolution safely.

Reviewed changes

Copilot reviewed 50 out of 50 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
testdata/tests/cases/compiler/declarationEmitVariableBindingPatternsRetained.ts Adds regression coverage.
testdata/submoduleAccepted.txt Registers accepted baseline differences.
testdata/baselines/reference/submoduleAccepted/conformance/stringLiteralTypesAndTuples01.js.diff Accepts tuple-pattern emit.
testdata/baselines/reference/submoduleAccepted/conformance/dependentDestructuredVariables.js.diff Accepts object-pattern emit.
testdata/baselines/reference/submoduleAccepted/compiler/isolatedDeclarationErrorsExpressions.errors.txt.diff Accepts isolated-declaration diagnostics.
testdata/baselines/reference/submoduleAccepted/compiler/destructuredDeclarationEmit.js.diff Accepts nested-pattern emit.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitRetainsJsdocyComments.js.diff Updates comment-preserving emit.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitOptionalMappedTypePropertyNoStrictNullChecks3.js.diff Accepts mapped-type pattern emit.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitOptionalMappedTypePropertyNoStrictNullChecks2.js.diff Accepts mapped-type pattern emit.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitOptionalMappedTypePropertyNoStrictNullChecks1.js.diff Accepts mapped-type pattern emit.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitNonExportedBindingPattern.js.diff Accepts non-exported patterns.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitExpressionInExtends6.js.diff Updates destructured class dependency emit.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitDestructuringPrivacyError.js.diff Updates privacy-case emit.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitDestructuringObjectLiteralPattern2.js.diff Accepts nested object patterns.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitDestructuringObjectLiteralPattern1.js.diff Accepts object patterns.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitDestructuringObjectLiteralPattern.js.diff Accepts comprehensive object patterns.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitDestructuringArrayPattern5.js.diff Accepts omitted array elements.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitDestructuringArrayPattern4.js.diff Accepts array rest patterns.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitDestructuringArrayPattern3.js.diff Accepts namespace array patterns.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitDestructuringArrayPattern2.js.diff Accepts nested array patterns.
testdata/baselines/reference/submoduleAccepted/compiler/declarationEmitDestructuringArrayPattern1.js.diff Accepts basic array patterns.
testdata/baselines/reference/submodule/conformance/stringLiteralTypesAndTuples01.js Updates tuple declaration output.
testdata/baselines/reference/submodule/conformance/dependentDestructuredVariables.js Updates object declaration output.
testdata/baselines/reference/submodule/compiler/isolatedDeclarationErrorsExpressions.errors.txt Removes binding-pattern diagnostics.
testdata/baselines/reference/submodule/compiler/destructuredDeclarationEmit.js Records nested destructuring output.
testdata/baselines/reference/submodule/compiler/declarationEmitRetainsJsdocyComments.js Records comments inside patterns.
testdata/baselines/reference/submodule/compiler/declarationEmitOptionalMappedTypePropertyNoStrictNullChecks3.js Records mapped-type pattern output.
testdata/baselines/reference/submodule/compiler/declarationEmitOptionalMappedTypePropertyNoStrictNullChecks2.js Records mapped-type pattern output.
testdata/baselines/reference/submodule/compiler/declarationEmitOptionalMappedTypePropertyNoStrictNullChecks1.js Records mapped-type pattern output.
testdata/baselines/reference/submodule/compiler/declarationEmitNonExportedBindingPattern.js Records non-exported patterns.
testdata/baselines/reference/submodule/compiler/declarationEmitExpressionInExtends6.js Records namespace destructuring.
testdata/baselines/reference/submodule/compiler/declarationEmitDestructuringPrivacyError.js Records privacy-case pattern.
testdata/baselines/reference/submodule/compiler/declarationEmitDestructuringObjectLiteralPattern2.js Records nested object patterns.
testdata/baselines/reference/submodule/compiler/declarationEmitDestructuringObjectLiteralPattern1.js Records object patterns.
testdata/baselines/reference/submodule/compiler/declarationEmitDestructuringObjectLiteralPattern.js Records comprehensive object patterns.
testdata/baselines/reference/submodule/compiler/declarationEmitDestructuringArrayPattern5.js Records omitted array elements.
testdata/baselines/reference/submodule/compiler/declarationEmitDestructuringArrayPattern4.js Records array rest patterns.
testdata/baselines/reference/submodule/compiler/declarationEmitDestructuringArrayPattern3.js Records namespace array patterns.
testdata/baselines/reference/submodule/compiler/declarationEmitDestructuringArrayPattern2.js Records nested array patterns.
testdata/baselines/reference/submodule/compiler/declarationEmitDestructuringArrayPattern1.js Records basic array patterns.
testdata/baselines/reference/conformance/dependentDestructuredVariablesNoCrash3.js Updates malformed-pattern emit baseline.
testdata/baselines/reference/compiler/subpathImportDeclarationEmit.js Preserves patterns across subpath imports.
testdata/baselines/reference/compiler/declarationEmitVariableBindingPatternsRetained.types Records inferred types.
testdata/baselines/reference/compiler/declarationEmitVariableBindingPatternsRetained.symbols Records symbol bindings.
testdata/baselines/reference/compiler/declarationEmitVariableBindingPatternsRetained.js Records JavaScript and declaration emit.
testdata/baselines/reference/compiler/declarationEmitSubpathImportsReexport.js Updates re-export declaration output.
internal/transformers/declarations/transform.go Retains variable binding patterns.
internal/pseudochecker/lookup.go Handles symbol-less variables.
internal/checker/nodebuilderimpl.go Resolves symbol-less declaration types.
internal/checker/emitresolver.go Avoids nil-symbol literal checks.

Comment thread internal/transformers/declarations/transform.go
Comment on lines +2 to +4
const func = () => "ok"
const b = { a: func }
export const { a } = b
@weswigham Wesley Wigham (weswigham) changed the title Retain binding patterns for variable declarations in declaration emit Retain uninitialized binding patterns for variable declarations in declaration emit Jul 28, 2026
-!!! error TS9019: Binding elements can't be exported directly with --isolatedDeclarations.
export const [, , b = 1]: [number, number, number | undefined] = [0, 1, 2];
~
!!! error TS9019: Binding elements can't be exported directly with --isolatedDeclarations. No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this need a refreshed message that mentions the initializer? Sort of curious how this differs from export const foo = 1, though

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sort of curious how this differs from export const foo = 1, though

The = 1 effectively removes the | undefined present in the type annotation for that member of the binding element - meaning that the type annotation alone won't give you the actual type of b. If we had a syntax like export const [,,b!]: [number, number, number | undefined], that'd work for the emit and we'd be able to always use the type annotation (simply replacing the initializer expression with an assertion), but... we do not have a "definitely assigned assertion" for binding elements (and even then, that's actually a questionable transform, since maybe the initializer still has undefined in its' type - there's really just no way around doing expression checking without an actual per-element type annotation!).

Does this need a refreshed message that mentions the initializer?

I can update it, if you'd like, since the cases when the error is emitted has been narrowed to only initialized binding elements.

@weswigham
Wesley Wigham (weswigham) added this pull request to the merge queue Jul 29, 2026
Merged via the queue into microsoft:main with commit d9773e3 Jul 29, 2026
21 checks passed
@weswigham
Wesley Wigham (weswigham) deleted the type-nodes-for-binding-patterns branch July 29, 2026 19:13
Jake Bailey (jakebailey) pushed a commit to jakebailey/TypeScript that referenced this pull request Aug 13, 2026
@thempatel

Copy link
Copy Markdown

hey team! i think this PR caused this regression. most of this is over my head but git bisect seems to point to this change

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Follow-up on issues/4254: typeof emit does not happen in export const { ... } = default

5 participants