-
Notifications
You must be signed in to change notification settings - Fork 26.8k
Description
Feature Request
Relevant Package
- @angular/forms
- Possibly any other package where null is used over undefined
Description
At the moment of writing this (June 2021), in the Angular code base, there seems to be no clear guideline for when to use null and when to use undefined. A brief search shows that (in the Angular code base starting from ./packages) assignment to null ( = null, notice the leading space to avoid matching === null) occurs 1448 times, and assignment to undefined ( = undefined) can be found 1905 times. While it is understandable to accept and properly handle passed null values from the point of view of public api (because Angular is a framework after all and users should be able to use whatever value they like), it is not understandable (to me), why null is used internally at all. This is problematic, because it makes it very easy for the null value to bleed through Angular's public api (which it shouldn't!).
(Imho) Nowadays, the type null just shouldn't be used in modern TypeScript code any more. The reasons for that are simple:
- TypeScript offers handy shortcuts to "add" the
undefinedtype to a type definition via?character: e.g.myClassPropertyOrMethodParam?: number. Usingnullinstead just feels awkward (e.g.myClassPropertyOrMethodParam: number | null) and makes the code less readable. In that case you will end sooner or later addingundefined, too (e.g.myClassPropertyOrMethodParam?: number | null, some people even prefer to addundefinedexplicitly in that case to "improve readability"myClassPropertyOrMethodParam: number | null | undefined). undefinedis the natural default type of anything that has not been initialized.- last but not least, the classic:
typeof null === 'object' // sadly true.
Consider Brendan Eich's two-word suggestion: "Use undefined"
Example where null bleeds through Angular API
There's one module where it particularly bothers me, that Angular uses null, because null bleeds through. What I mean by "bleeding through" is, that the null type is exposed via API that is consumed by Angular users:
The @angular/forms package assigns null as the default value to a form control! See here and here!
Why is this a problem?
This is a serious problem (imho)! What Angular is doing here is very offensive! It is forcing its users (or say at least it's tricking its users below senior level, which could well be >80%) to include the null type in their own API / interfaces, because it's just possible that a form control is in that state! This can make code more complicated than it has to be. It actively hinders people from trying to avoid null inside their own code base. For example what I can see regularly in our code base are things like this:
export interface SomeType {
someProperty: number;
someOptionalProperty?: string | null
}
When I ask them why they've included null in their type, what I usually hear as an explanation is "because otherwise it would not have been compatible with Angular Forms API".
To be clear: while adding null to someOptionalProperty is no harm, it is just plain unnecessary here! While it looks like no big deal, it really is! Like cancer, adding null to your types can spread easily to other places in your code base. A method that in the past was properly typed with optional parameters (param?: SomeType) will soon be widened to accept null as well (param?: SomeType | null). This is, because in a lot of projects, developers just need to get work done, so it's understandable why they're saying "it's easier than fixing the null type in my interface right now" and "I'm in a hurry and need to call that method now!".
Where null can't be avoided
You can't always avoid having null values. This is, because JSON doesn't know the type undefined, it only knows null. However, in my eyes, this is not an excuse to carry the null type around all over the code base. I'm not saying to not accept null values coming in from JSON. All I'm saying is to stop using null actively.
How does a code base not using null at all look like?
When following a few coding guidelines, null can always be implicitly treated as undefined and thus there's no need to add it to any types / interfaces at all.
Here are the guidelines that make it possible:
- avoid direct undefined type guards (e.g.
if (value === undefined) { ... }. - Instead, use indirect type guards (aka truthiness checks) e.g.
if (value) { ... } - Whenever 0 or empty strings are meaningful, use either
- an explicit helper method like Lodash's
isNil - or include the meaningful value in the comparison (e.g.
if (!value && value !== 0) { ... })
- an explicit helper method like Lodash's
- Consider using a lint rule that disallows the usage of
null
Describe the solution you'd like to see in Angular
- all public api should continue to accept
null(ideally only as part ofanytype) and handle it properly - all public api should stop returning
nullvalues - all public api that used to return
nullvalues should returnundefinedinstead ofnull
Consequences for Angular
I know that this is a huge change and a breaking one as well. A rather long deprecation period would therefore be needed for user adoption.
Describe alternatives you've considered
As it is a matter of (admittedly very debatable) taste, there will surely exist a multitude of alternatives and other opinions. I would like to not open up discussion here on how null is useful to somebody in some cases. Such a discussion can be found here ... Instead, please just up/downvote this feature request if you agree/disagree. Thanks a lot!
Best Regards, Nic