Skip to content

feat(compiler): Angular expressions with optional chaining returns undefined#68084

Open
JeanMeche wants to merge 4 commits intoangular:mainfrom
JeanMeche:optional-chaining-specs
Open

feat(compiler): Angular expressions with optional chaining returns undefined#68084
JeanMeche wants to merge 4 commits intoangular:mainfrom
JeanMeche:optional-chaining-specs

Conversation

@JeanMeche
Copy link
Copy Markdown
Member

@JeanMeche JeanMeche commented Apr 8, 2026

To mitigate this breaking change, this behavior can be disabled by wrapping expressions with the $safeNavigationMigration magic function.
: $safeNavigationMigration(foo?.bar?.baz)

fixes #34385, #37622

BREAKING CHANGE: By default optional chainings will now return undefined instead of null. This behavior can be disabled by wrapping expressions with the $safeNavigationMigration magic function.
: $safeNavigationMigration(foo?.bar?.baz)

@angular-robot angular-robot Bot added detected: breaking change PR contains a commit with a breaking change detected: feature PR contains a feature commit area: compiler Issues related to `ngc`, Angular's template compiler labels Apr 8, 2026
@ngbot ngbot Bot added this to the Backlog milestone Apr 8, 2026
@JeanMeche JeanMeche force-pushed the optional-chaining-specs branch 16 times, most recently from f9e97c4 to a5367d3 Compare April 11, 2026 16:09
@JeanMeche JeanMeche force-pushed the optional-chaining-specs branch from a5367d3 to b2de89a Compare April 16, 2026 16:49
@JeanMeche JeanMeche marked this pull request as ready for review April 16, 2026 16:49
@JeanMeche JeanMeche force-pushed the optional-chaining-specs branch from b2de89a to 778f184 Compare April 16, 2026 16:50
@JeanMeche JeanMeche added the target: major This PR is targeted for the next major release label Apr 16, 2026
@JeanMeche JeanMeche modified the milestones: Backlog, v22 candidates Apr 16, 2026
@JeanMeche JeanMeche requested review from alxhub and removed request for devversion April 16, 2026 16:54
Copy link
Copy Markdown
Member

@JoostK JoostK left a comment

Choose a reason for hiding this comment

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

Initial round of comments, I haven't gone over the tests nor JIT code yet, and possibly more is pending.

_experimentalAllowEmitDeclarationOnly?: boolean;
generateDeepReexports?: boolean;
generateExtraImportsInLocalMode?: boolean;
legacyOptionalChaining?: boolean;
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.

The LS tsconfig-ng.schema.json would need to be updated.

But, the flag was discussed to be 1P only and therefore not publicly supported, did this change?

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.

Yes the flag should be 1P only.
This is BazelAndG3Options which isn't public afaik.

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.

This is BazelAndG3Options which isn't public afaik.

It sorta is, reflected by the public api golden update. It's just its internal interface for grouping that reflects BazelAndG3. Perhaps they aren't meant to be publicly supported, but the current structuring of these options makes them 3P public in my view.

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.

Yeah I see where you come from.
I don't think we document BazelAndG3Options (beside annotateForClosureCompiler https://angular.dev/reference/configs/angular-compiler-options#annotateforclosurecompiler)

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.

Considering that @angular/compiler-cli isn't considered public API at all perhaps this is fine if it's not documented, but I do think it's confusing. Perhaps prefixing with an underscore would underpin its not supported status.


return {
...baseMeta,
legacyOptionalChaining: major < 22 && version !== PLACEHOLDER_VERSION,
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.

This is used in more places, but PLACEHOLDER_VERSION is susceptible to problems as it is stamped:

https://hyrious.me/npm-browser/?q=@angular/compiler-cli@21.2.9/package/linker/src/file_linker/partial_linkers/util.d.ts:10

whereas this should always be comparing to the literal 0.0.0-PLACEHOLDER.

Easily avoided using

// Declared using string concatenation to avoid this from being stamped.
const PLACEHOLDER_VERSION = '0.0.0' + '-PLACEHOLDER';

perhaps best to address in a separate PR, as this is independent and not necessarily a problem today.

Comment thread packages/compiler-cli/src/ngtsc/core/api/src/public_options.ts Outdated
Comment thread packages/compiler-cli/src/ngtsc/translator/src/typescript_ast_factory.ts Outdated
Comment thread packages/core/src/render3/interfaces/public_definitions.ts Outdated
@JeanMeche JeanMeche force-pushed the optional-chaining-specs branch 5 times, most recently from 3c53a74 to 07fa535 Compare April 23, 2026 14:11
Copy link
Copy Markdown
Member

@JoostK JoostK left a comment

Choose a reason for hiding this comment

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

Few more comments. I am not clear on why the original safe AST nodes aren't used for this, instead of the introduction of isOptional (see one of the comments).

Comment thread packages/compiler-cli/test/compliance/test_helpers/check_expectations.ts Outdated
Comment thread packages/compiler/src/output/output_ast.ts
Comment thread packages/compiler/src/render3/partial/api.ts Outdated
Comment thread packages/compiler/src/template/pipeline/src/phases/safe_navigation_migration.ts Outdated
Comment thread packages/compiler/src/typecheck/ops/expression.ts
Comment thread packages/compiler/src/typecheck/api.ts Outdated
Comment thread packages/core/test/acceptance/expressions_spec.ts
…ndefined`

To mitigate this breaking change,  this behavior can be disabled by wrapping expressions with the `$null` magic function.
: `$null(foo?.bar?.baz)`

fixes angular#34385, angular#37622

BREAKING CHANGE: By default optional chainings will now return `undefined` instead of `null`.  This behavior can be disabled by wrapping expressions with the `$null` magic function.
: `$null(foo?.bar?.baz)`
@JeanMeche JeanMeche force-pushed the optional-chaining-specs branch from 07fa535 to dd87d90 Compare April 26, 2026 21:27
@JeanMeche JeanMeche force-pushed the optional-chaining-specs branch from dd87d90 to 466bf4c Compare April 26, 2026 22:08
@pullapprove pullapprove Bot requested a review from kirjs April 27, 2026 11:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: compiler Issues related to `ngc`, Angular's template compiler detected: breaking change PR contains a commit with a breaking change detected: feature PR contains a feature commit target: major This PR is targeted for the next major release

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Align with the optional chaining spec

2 participants