Skip to content

Commit 4c2a730

Browse files
committed
types-grammar, ch1: tweaks to nullish and non-nullish discussion
1 parent 3260c68 commit 4c2a730

File tree

1 file changed

+32
-6
lines changed

1 file changed

+32
-6
lines changed

types-grammar/ch1.md

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ JS variables themselves don't have types. They hold any arbitrary value, which i
5252

5353
The `null` and `undefined` types both typically represent an emptiness or absence of value.
5454

55-
The `null` value-type has an unexpected `typeof` result. Instead of `"null"`, we see:
55+
Unfortunately, the `null` value-type has an unexpected `typeof` result. Instead of `"null"`, we see:
5656

5757
```js
5858
typeof null; // "object"
@@ -79,13 +79,13 @@ typeof whatever[10]; // "undefined"
7979

8080
| NOTE: |
8181
| :--- |
82-
| The `typeof nonExistent` expression is referring to an undeclared variable `nonExisttent`. Normally, accessing an undeclared variable reference would cause an exception, but the `typeof` operator is afforded the special ability to safely access even non-existent identifiers and calmly return `"undefined"` instead of throwing an exception. |
82+
| The `typeof nonExistent` expression is referring to an undeclared variable `nonExistent`. Normally, accessing an undeclared variable reference would cause an exception, but the `typeof` operator is afforded the special ability to safely access even non-existent identifiers and calmly return `"undefined"` instead of throwing an exception. |
8383

8484
However, each respective "empty" type has exactly one value, of the same name. So `null` is the only value in the `null` value-type, and `undefined` is the only value in the `undefined` value-type.
8585

8686
#### Null'ish
8787

88-
Semantically, `null` and `undefined` types both represent emptiness, or absence of another affirmative, meaningful value.
88+
Semantically, `null` and `undefined` types both represent general emptiness, or absence of another affirmative, meaningful value.
8989

9090
| NOTE: |
9191
| :--- |
@@ -95,7 +95,7 @@ For a lot of JS, especially the code developers write, these two *nullish* value
9595

9696
JS provides a number of capabilities for helping treat the two nullish values as indistinguishable.
9797

98-
For example, the `==` (coercive-equality comparision) operator specifically treats `null` and `undefined` as coercively equal to each other, but to no other values in the language. As such, as `.. == null` check is safe to perform if you want to check if a value is specifically either `null` or `undefined`:
98+
For example, the `==` (coercive-equality comparision) operator specifically treats `null` and `undefined` as coercively equal to each other, but to no other values in the language. As such, a `.. == null` check is safe to perform if you want to check if a value is specifically either `null` or `undefined`:
9999

100100
```js
101101
if (greeting == null) {
@@ -140,9 +140,33 @@ Just to be clear: `record?.` is saying, "check `record` for nullish before `.` p
140140
| :--- |
141141
| Some JS developers believe that the newer `?.` is superior to `.`, and should thus almost always be used instead of `.`. I believe that's an unwise perspective. First of all, it's adding extra visual clutter, which should only be done if you're getting benefit from it. Secondly, you should be aware of, and planning for, the emptiness of some value, to justify using `?.`. If you always expect a non-nullish value to be present in some expression, using `?.` to access a property on it is not only unnecessary/wasteful, but also could potentially hide future bugs where your assumption of value-presence had failed but `?.` covered it up. As with most features in JS, use `.` where it's most appropriate, and use `?.` where it's most appropriate. Never substitute one when the other is more appropriate. |
142142
143-
#### Distint'ish
143+
There's also a somewhat strange `?.[` form of the operator, not `?[`, for when you need to use `[ .. ]` style access instead of `.` access:
144144
145-
It's important to keep in mind that `null` and `undefined` *are* actually distinct types, and thus `null` is quite noticeably distinct from `undefined`. You can, carefully, construct programs that mostly treat them as indistinguishable. But that requires care and discipline by the developer. From JS's perspective, they're often distinct.
145+
```js
146+
record?.["shipping" + "Address"]?.state; // XY
147+
```
148+
149+
Yet another variation, referred to as "optional-call", is `?.(`, and is used when conditionally calling a function if the value is non-nullish:
150+
151+
```js
152+
// instead of:
153+
// if (someFunc) someFunc(42);
154+
//
155+
// or:
156+
// someFunc && someFunc(42);
157+
158+
someFunc?.(42);
159+
```
160+
161+
The `?.(` operator seems like it is checking to see if `someFunc(..)` is a valid function that can be called. But it's not! It's only checking to make sure the value is non-nullish before trying to invoke it. If it's some other non-nullish but also non-function value type, the execution attempt will still fail with a `TypeError` exception.
162+
163+
| WARNING: |
164+
| :--- |
165+
| Because of that gotcha, I *strongly dislike* this operator form, and caution anyone against ever using it. I think it's a poorly conceived feature that does more harm (to JS itself, and to programs) than good. There's very few JS features I would go so far as to say, "never use it." But this is one of the truly *bad parts* of the language, in my opinion. |
166+
167+
#### Distinct'ish
168+
169+
It's important to keep in mind that `null` and `undefined` *are* actually distinct types, and thus `null` can be noticeably different from `undefined`. You can, carefully, construct programs that mostly treat them as indistinguishable. But that requires care and discipline by the developer. From JS's perspective, they're more often distinct.
146170
147171
There are cases where `null` and `undefined` will trigger different behavior by the language, which is important to keep in mind. We won't cover all the cases exhaustively here, but here's on example:
148172
@@ -160,6 +184,8 @@ greet(null); // null
160184
161185
The `= ..` clause on a parameter is referred to as the "parameter default". It only kicks in and assigns its default value to the parameter if the argument in that position is missing, or is exactly the `undefined` value. If you pass `null`, that clause doesn't trigger, and `null` is thus assigned to the parameter.
162186
187+
There's no *right* or *wrong* way to use `null` or `undefined` in a program. So the takeaway is: be careful when choosing one value or the other. And if you're using them interchangeably, be extra careful.
188+
163189
### Boolean Values
164190
165191
The `boolean` type contains two values: `false` and `true`.

0 commit comments

Comments
 (0)