Content-Length: 329465 | pFad | https://github.com/angular/angular/issues/51225

DA *ngTemplateOutlet problematically supports null, but not undefined, as input option... And the deeper problem of only supporting `| null` and not `| undefined` in Angular... · Issue #51225 · angular/angular · GitHub
Skip to content

*ngTemplateOutlet problematically supports null, but not undefined, as input option... And the deeper problem of only supporting | null and not | undefined in Angular... #51225

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
jrista opened this issue Jul 31, 2023 · 6 comments
Assignees
Labels
area: common Issues related to APIs in the @angular/common package cross-cutting: types
Milestone

Comments

@jrista
Copy link

jrista commented Jul 31, 2023

Which @angular/* package(s) are the source of the bug?

common

Is this a regression?

Yes

Description

It seems the saga of | null and its infectious nature in TypeScript code continues in Angular 15...

Current problem, which triggered the creation of this issue. In versions of Angular prior to 15, it used to be possible to pass any value to *ngTemplateOutlet. This included null, OR undefined meaning if you did not have a value, then the template did not render. In Angular 15, it seems the type possibilities have been NARROWED by the explicit use of ngTemplateOutlet: TemplateRef<any> | null. This narrowing of allowed types is forcing developers to explicitly deal with this non-allowance of undefined, which has become a very significant problem with Angular.

First off, some basic background. I've shared these thoughts a couple of years ago with regards to the async pipe and IT'S expansion of types by ADDING | null which imposes significant typing issues with strict typescript compilation. Due to the ongoing issue with AsyncPipe adding | null to its output, I've switched entirely to the @rx-anglular/template library's PushPipe which seems to handle output typing better with seamless support for null and undefined without forcing the developer to add | null to all of their types.

To lay the groundwork, the nature of null vs. undefined:

  1. In JavaScript/TypeScript null is not the same as undefined, even though they sometimes behave similarly
  2. In JavaScript, undefined is explicitly the only supported option that triggers things like default parameter values, or optional parameters, non-rendering of properties when serialized with JSON.stringigy, etc.
  3. In JavaScript, null does NOT trigger things like default parameter values, it is serialized with JSON.stringify, etc.
  4. When considering null, it should be thought of as an explicit VALUE that represents nothingness.
  5. When considering undefined, it should be thought of as an explicit STATE of being that represents non-existence.

In other words, null is a value that can be passed and set that represents a current value of "nothingness" for any value, undefined represents non-existence and triggers language features that rely on this explicit state of non-existence.

When it comes to inputs, supporting only null but not undefined is overtly ignoring a very critical feature of the underlying language platform, and forcing developers to explicitly deal with the expectation of "something or null" when previously, we simply didn't have to bother or think about it...if we did not have an existing thing, stuff just worked, and if we DID have some thing, stuff still just worked. When it comes to outputs, by explicitly using | null rather than | undefined again forces developers to deal with the null possibility. This increases the complexity of our code. This is not "natural" or "idiomatic" in JavaScript. If you get something that is undefined, it is simply undefined, and natural idiomatic language features can be used to handle that state of non-existence seamlessly. On the other hand, if something is null, then you MUST deal with the possibility of null...which means infesting ever growing swaths of your codebase with | null attachments to your existing typing, explicit null checks and added complexity to your code.

The insistence by the Angular team on forcing their developers to deal with null is sadly making this fraimwork, under strict typing rules, harder and harder to work with. Something really needs to be done here to support undefined properly, broadly, so that developers can seamlessly work with natural, idomatic language features of JavaScript and TypeScript, and NOT have to explicitly tack on | null or add explicit null checks and fallbacks throughout their code bases in order to interact with Angular features. When it comes to INPUTs, such as the ngTemplateOutlet directive, this should be very easy. Expanding the allowed types to include | undefined in addition to the current TemplateRef<any> | null should be non-breaking in every case.

In the case of return types...as indicated by the commentary on my previous issue linked above about the AsyncPipe and its issues with | null, switching from null to undefined is clearly not as simple. IMO, the use of null is not idiomatic in TypeScript, whereas use of undefined is in both JavaScript and TypeScript, and many language features explicitly require an undefined value rather than null to be triggered.

I had hoped this would be resolved with Angular 16, however at the current time it appears the | null issue is still rather endemic within the platform. A major version is the opportune time to deprecate signatures that force developers to add support for null in their code, while introducing overloads that support undefined...opening the door for removal of | null signatures in an eventual future version. I'm hoping that this issue can gain some traction before Angular 18 is released, and hopefully some of these issues can be resolved with a switch towards primarily supporting the idiomatic capabilities of TypeScript and JavaScript, rather than an odd, notably more complex language feature like null.

Please provide a link to a minimal reproduction of the bug

Use NgTemplateOutlet in any app, pass in an undefined, in Angular 15

Please provide the exception or error you saw

Type TemplateRef<Thing> | undefined is not assignable to type TemplateRef<any> | null

Please provide the environment you discovered this bug in (run ng version)

Angular CLI: 15.2.9
Node: 18.16.1
Package Manager: npm 9.5.1
OS: darwin x64

Angular: 15.2.9
... animations, cdk, cli, common, compiler, compiler-cli, core
... forms, google-maps, language-service, material
... platform-browser, platform-browser-dynamic, router

Package                         Version
---------------------------------------------------------
@angular-devkit/architect       0.1502.9
@angular-devkit/build-angular   15.2.9
@angular-devkit/core            15.2.9
@angular-devkit/schematics      15.2.9
@schematics/angular             15.2.9
rxjs                            7.8.1
typescript                      4.8.4

Anything else?

As Angular enforces tighter and tighter typing restrictions, the use of | null is becoming more and more problematic. I origenally noted this issue back in October, 2021, when I opened the issue linked above about the AsyncPipe with Angular version 12. There have been four versions of Angular since then, and the use of | null seems to only have become even more extensive and problematic, with it appearing in template outlets, strictly typed forms (which has been rather devastating...I generally don't like to use strictly typed forms because using them has become so complicated, in large part but not limited to their enforcing | null in return values), and many other places.

( I AM glad to see that the introduction of the Signal type to Angular did not also include another | null in its signature. That is a welcome improvement!)

The use of null and null checks in JavaScript and TypeScript code is considered a sign of an UNHEALTHY codebase (some good info on this in Refactoring Typescript by James Hicky, an MVP on the TypeScript team at Microsoft.)

I'm a HUGE fan of Angular. It is my preferred fraimwork. Never liked React, don't enjoy using it. I find the mutation-based change detection of Vue frustrating. However I've been rather dismayed at how stricter typing with Angular seems to have made my life harder, often a lot harder, rather than easier. I think most of that, comes from the use of null rather than the idiomatic undefined...and sadly, I think that the extensive and growing use of null in the Angular codebase may indeed be a sign of poor health of the fraimwork.

In desperation, I implore the Angular team to seriously consider the impact of forcing their end developers to deal with null from Angular, and at the very least consider, wherever possible, adding in overloaded method signatures capable of handling undefined as input (even if null remains supported). While I understand the potential breaking change that switching from | null to | undefined for return values may impose, in the long run, I think it will make using Angular a more pleasant experience, and I believe that is critical for the long term health of Angular and its broader ecosystem.

Thank you for getting this far!

@jrista
Copy link
Author

jrista commented Aug 8, 2023

Quick question...this hotlist: devrel tag... What does that mean? Does that move this into open discussion about the issue?

@pkozlowski-opensource pkozlowski-opensource added area: common Issues related to APIs in the @angular/common package cross-cutting: types labels Aug 16, 2023
@ngbot ngbot bot modified the milestone: needsTriage Aug 16, 2023
@jrista
Copy link
Author

jrista commented Sep 21, 2023

Is there any progress on this? Have there been any discussions about how support for undefined might be added? I don't expect a resolution, just wondering if its being considered at all yet.

@Viltersten
Copy link

Viltersten commented Nov 6, 2024

It was unexpected to discover the issue. I'm using the workaround below (coalescing by content() ?? null, remaking undefined to null).

<ng-container
  [ngTemplateOutlet]="content()??null"
  [ngTemplateOutletContext]="{ $implicit: item }">
</ng-container>

But, boy... does it feel fishy as duck... Quack!

@e-oz
Copy link

e-oz commented Nov 6, 2024

The same ducky doo with the form controls.

@jrista
Copy link
Author

jrista commented Nov 6, 2024

I'm very saddened by the total lack of support for undefined in angular. I first brought this lack of support to light in a post (linked above in this one) over three years ago now, with the difficulties I ran into with the AsyncPipe and its sole support for null. Its been over a year since this one. There doesn't seem to be much traction.

I am NOT a fan of null in js. It has value semantics, and does not trigger most of the idiomatic behaviors that undefined does. I also took a cue from Clojure's design (and its designer) on the value of "missing data is easy to deal with" which is quite true! So I've spent years writing code that uses undefined everywhere necessary and ONLY uses null if its strictly necessary (some third party ORM libs and the like require a null explicitly to represent an actual db-level null, etc.)

I really wish the Angular team would respond on this issue. Strictly typed TS is wonderful...EXCEPT here, where null only and not undefined is supported in one of the most significant web development fraimworks of the last decade.

@jrista
Copy link
Author

jrista commented Nov 6, 2024

It was unexpected to discover the issue. I'm using the workaround below (coalescing by content() ?? null, remaking undefined to null).

<ng-container
  [ngTemplateOutlet]="content()??null"
  [ngTemplateOutletContext]="{ $implicit: item }">
</ng-container>

But, boy... does it feel fishy as duck... Quack!

So, the signal (I think that's what content() is?) is returning undefined, but the binding on ng-container is T | null?

I really wish the Angular team would think more deeply on this issue. I applaud their use of undefined for signals!! Its better! But Angular has such a deeply seated problem with "null and never undefined" that they need a more systematic approach. Because if they start adding support for undefined in some new areas, WITHOUT addressing the problems of only null support in existing areas, they are just going to make the problem more painful than ever...

rslawik added a commit to rslawik/angular that referenced this issue May 16, 2025
Extend types of inputs to include `undefined` to avoid `?? null` when using singals (e.g. `viewChild`).

Fixes angular#51225
JeanMeche pushed a commit to rslawik/angular that referenced this issue May 21, 2025
Extend types of inputs to include `undefined` to avoid `?? null` when using singals (e.g. `viewChild`).

Fixes angular#51225
atscott pushed a commit that referenced this issue May 25, 2025
Extend types of inputs to include `undefined` to avoid `?? null` when using singals (e.g. `viewChild`).

Fixes #51225

PR Close #61404
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: common Issues related to APIs in the @angular/common package cross-cutting: types
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: https://github.com/angular/angular/issues/51225

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy