feat(compiler): add nativeOptionalChainingSemantics option#67068
feat(compiler): add nativeOptionalChainingSemantics option#67068kbrilla wants to merge 1 commit intoangular:mainfrom
Conversation
|
Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). View this failed invocation of the CLA check for more information. For the most up to date status, view the checks section at the bottom of the pull request. |
|
We usally try distance us from introducing new properties to the existing decorators. Also we prefer to not have local behavior like this. Let me bring the suggestion to the team. |
Thanks for having a look at it! I went with this approach as every other I could think of would be compleatly breaking existing code or introducing really 'not pretty' migration. This approach is similar to Default/OnPush/Standalone:true/false and introduce similar granual adaptation as standalone allowed. Still, I'm happy it did not got denied straight away :) |
|
I also forgot to mention that with inlay hints from my other pr it works be more visible what is actuall behaviour without looking at the component directive flag |
Add a compiler option that aligns Angular template safe navigation (?.) with native ECMAScript optional chaining behavior. When enabled, a?.b evaluates to undefined (instead of null) at runtime when a is nullish. Includes: - nativeOptionalChainingSemantics tsconfig option (project-wide) - Per-component optionalChainingSemantics metadata override - Host binding and hostDirective support (each uses own semantics) - Extended template diagnostic NG8119 for legacy usage detection - Migration schematic: ng generate @angular/core:optional-chaining-semantics-migration - Partial linker support for library distribution - JIT support via setJitOptions() - Documentation in adev/src/content/tools/cli/template-typecheck.md Fixes angular#34385, angular#37622, angular#37619
c99cfe4 to
dfae32f
Compare
This PR introduces
nativeOptionalChainingSemantics, a compiler option that aligns Angular template safe navigation (?.) with native ECMAScript optional chaining behavior.Problem
Angular's safe navigation operator (
?.) has historically returnednullwhen short-circuiting, while JavaScript/TypeScript's optional chaining returnsundefined. This causes subtle bugs:config?.timeout ?? 30behaves differently in templates vs TypeScript — in templates,nullpasses through??when it shouldn'tconfig?.timeout === undefinedisfalsein templates buttruein TypeScript| undefined, creating a mismatch between static types and runtime behaviorCommunity issues: #34385, #37622, #37619
Solution
Compiler option:
nativeOptionalChainingSemantics{ "angularCompilerOptions": { "nativeOptionalChainingSemantics": true } }When enabled,
a?.bevaluates toundefined(instead ofnull) at runtime whenais nullish, matching JavaScript/TypeScript semantics.Per-component override:
optionalChainingSemanticsComponents and directives can override the project-wide setting:
This enables gradual migration — individual components can opt in/out independently, and the setting is preserved in partial declarations for library distribution.
Host bindings & directives
Each directive/component uses its own semantics independently, including:
[attr.x],[class.x],[style.x])hostDirectives— each keeps its own semantics regardless of the parent componentExtended template diagnostic: NG8119
When
nativeOptionalChainingSemanticsis enabled project-wide, components that haven't adopted native semantics (or use explicit'legacy') receive an informational diagnostic (NG8119) flagging?.usage that returnsnullinstead ofundefined.Migration schematic
Uses AST-based analysis to identify
?.usage in templates. The migration adds?? nullcoalescing where needed for components that depend on thenullreturn value, making them safe to enable native semantics.Design note: The migration does NOT blindly add
?? nulleverywhere — it analyzes usage patterns (strict equality checks, nullish coalescing, ternary fallbacks) and only patches expressions where the null-to-undefined change would alter observable behavior.Partial linker support
The
optionalChainingSemanticsmetadata is written into partial declarations (ɵɵngDeclareComponent/ɵɵngDeclareDirective) so the linker respects the intended behavior when consuming pre-compiled libraries.Documentation
Updated
adev/src/content/tools/cli/template-typecheck.mdwith a new "Optional chaining semantics" section covering the option, migration, and caveats.Implementation details
expand_safe_readsphase checks the compilation unit'soptionalChainingSemanticsand emits eithernullorundefinedfor the safe ternary fallbacknativeOptionalChainingSemanticsis available viasetJitOptions()for JIT-compiled componentsWhat this does NOT change
nullbehavior)Live Demo
A complete demo application showcasing the feature is available at:
https://kbrilla.github.io/angular-next-features/
It demonstrates: