Is a "When in doubt, use optional chaining" a valid approach?

Like maybe I am missing something here, but in Step 40 of ‘Learn Basic String and Array Methods by Building a Music Player,’ there is a note that states: ‘You should not use the optional chaining operator ?. in this step because userData.currentSong will not be null or undefined at this point,’ which leads me to believe that optional chaining should only be used if a value could potentially be null or undefined.

However, in step 43, I am told “add an if to check if userData?.currentSong is null”

Further, in step 44, I am told to add an else block and call the playSong function “with the id of the currently playing song as an argument”, so my code is supposed to look like this:

if (userData?.currentSong === null) {
playSong(userData?.songs[0].id);
} else {
playSong(userData?.currentSong.id)
}

While I do get that we would need to use optional chaining for the playSong block (playSong(userData?.songs[0].id);)*, I do not get why we need to use optional chaining for the other two blocks:

At the start of our code, we initialized userData like this:
let userData = {
songs: […allSongs],
currentSong: null,
songCurrentTime: 0,
};

meaning it will always exist, even if all songs are deleted, so it will never be undefined.

Also, for the playSong with currentSong block(playSong(userData?.currentSong.id)), I don’t see why we need optional chaining here either, given that the if condition before this ensures currentSong is not null or undefined in the else block, therefore valid.

Currently,
if (userData.currentSong === null) {
playSong(userData?.songs[0].id);
} else {
playSong(userData.currentSong.id)
}
is not accepted and I am wondering what is the purpose here, assuming that “When in doubt, use optional chaining” is not a valid approach. (Google seems to think it isn’t, and trying to understand why in step 44 “playSong(userData.currentSong.id)” was not accepted is what got me confused. Did at first not note it in step 43, as it explicitly tells me to “call the playSong() function with the id of the first song in the userData*?**.songs* array.”, but in step 44, it does not say that, so I can’t see a reason why we need to use optional chaining here…)

PS: There seem to be an additional 3 or 4 cases where optional chaining is used, but it appears to me that it would not be needed.

Any insights would be great as to why it is the way it is currently.

  • Optional chaining is necessary because the user has the option to delete all songs, and than the songs[0] property will not exist, which will cause an error.

After reading pkdvalis post What Is the Optional Chaining Operator, and How Does It Work? I also believe that I would not even need optional chaining on

playSong(userData?.songs[0].id);

as optional chaining is basically pointless for missing properties: By default, missing properties will throw undefined, and optional chaining will not change that.

the optional chaining there is useuful and protects from error if userData can be undefined

Thanks for coming to my ted talk!

My thread is me trying to understand that operator and check if the lesson/quiz is mis-worded. I’m trying to present my case but I just learned about it for the first time yesterday so I would assume that I’m incorrect.

Can you provide a link to this project please?

If I understand correctly:

The ?. here is only checking if the object userData is defined.

songs[0] is also an object because it has leaf nodes (.id). But if songs[0] is undefined you would use the operator on it like this:

userData?.songs[0]?.id

Also, I realize now that you by definition cannot even use ?. on a leaf node property since nothing is chained after those. For example these are syntax errors:

userData.songs[0].id?
userData.songs[0].id?.

?. can only be used when something follows in the chain, and it checks the preceding value, which must be an object. If the leaf node exists or not doesn’t really make a difference.

You say

"optional chaining there is useuful and protects from error if userData can be undefined "

but please help me understand: Why would userData ever be undefined? userData is always initialized at the start and will never be null or undefined unless explicitly overwritten in the code, which doesn’t happen here.

Basically, it is as if we try to insure against something that does not exist. And step 40 tells us

" You should not use the optional chaining operator ?. in this step because userData.currentSong will not be null or undefined at this point."

So I read this as “If we know userData will not be null or undefined, than we should not use it.”

and because we initialized it at the beginning of our code, we know it will not be null or undefined.

I am just trying to understand.

I don’t know, that is why there is an “if” in that sentence, if it can be null or undefined, then the optional chaining is useful

Here is the link for “Optional chaining is necessary because…” https://www.freecodecamp.org/learn/javascript-algorithms-and-data-structures-v8/learn-basic-string-and-array-methods-by-building-a-music-player/step-40

It is the seventh course in “JavaScript Algorithms and Data Structures” as part of “Our archived coursework” (https://www.freecodecamp.org/learn)

“The ?. here is only checking if the object userData is defined.”
That’s the way I understand it too. However, despite what my name may suggest, I am as new to programming as can be.

" But if songs[0] is undefined you would use the operator on it like this: "

userData?.songs[0]?.id

Again, it would only check whether the userData and songs objects are null or undefined. Which they will not be, as they where initialized at the top of the code. Because songs is also an object that can be empty if the songs in the playlist are deleted, I thought that optional chaining protects against throwing an error when a property does not exist, which is why I wrote the last sentence in my original post. But the only thing it protects against, is that if you try to access a property of an object that does not exists. So if we delete every single song, and the songs object is empty, it still is not null or undefined, which is why I made the second comment: and so I still don’t see why I should use optional chaining for anything here.

Not sure if this will be a good answer but:

userData?.songs[0].id

There’s a difference between you the programmer knowing that userData always exists because you defined it, and the line accessing the object knowing it exists. Maybe you refactor the code later, or if it’s part of a larger codebase.

There’s also a difference between knowing it exists because we defined it, and knowing it doesn’t exist because we didn’t define it. We’re not using ?. because we know it’s not defined, we’ll use it because we’re not sure what the state might be in the future when this line runs, but we still want to make sure there will be a consistent result.

Not only can userData.currentSong be null, it is even initialized as null.
But that is userData.currentSong, and userData.currentSong only!

But take a look at it line by line:
if (userData?.currentSong === null) {
We know for certain that userData is neither null nor undefined! So why should we use optional chaining on userData?

Now again, tho only Object inside the if-else blocks that can be null or undefined is the currentSong Object. And if it is indeed null, we want to play the first song:
playSong(userData?.songs[0].id);
But here again, we are using optional chaining on an object that we know for sure is initialized and neither null nor undefined.
Same as with the else block:
} else { playSong(userData?.currentSong.id); }
Again we know that userData is initialized.

So the if statement is never to determine whether userData is null or undefined, but to determine whether the currentSong object is null. And if it is, we have code in place on how to handle it. So this was not really helpful: userData.currentSong can be undefined, but not userData.

Not sure I am following:
I mean sure, you are right, at the time when we write this, we may not know what will happen later: We could later add a button to delete all Songs. And in the process, we somehow delete the userData object. (Of course we would have to recreate it in inside the resetplaylist block later)

And if that is what we plan on doing, than we should use optional chaining.

However, that is exactly my big question here: Is “when in doubt, use optional chaining” a valid approach?

Because the only reason I think optional chaining should be used, is if we believe there will be an instance where we may end up needing it, i.e. we have reason to believe the user could delete userData. But to simply future proof for something we have no reason to believe is the case, I can’t see how that can be useful, and this is confirmed in step 40: ‘You should not use the optional chaining operator ?. in this step because userData.currentSong will not be null or undefined at this point,’

We know it will neither be null nor undefined in any one of the three instances used here.

But take all this with a grain of salt, because this is just what I believe from the information I have gathered, but I started coding this year and will be glad if anyone corrects me.

always using optional chaining is not a good choice, you can be suppressing useful errors to understand why your app is not working, and would need a lot more debugging to find hidden bugs

1 Like

Ok, does that than mean that essentially you are agreeing withe me and that optional chaining should not have been used in any one of the three instances it was used here?

I may come off as a smartass, but I really am just trying to understand. And the way I understand it right now, I can not find a single optional chaining instance in the code where userData could be null or undefined, therefore I am taking it to mean that it is entirely redundant…

maybe it was something that was intended to be added as a topic but there wasn’t a better option :person_shrugging:

Normally, I would tell you to open an issue, but as it is archived coursework, it will not get the amount of work needed to fix this.

Instead maybe I can suggest you to move to the full stack curriculum

1 Like

now that I remember, there is a Music Player in full stack, but it has been updated, and it has only one instance of optional chaining iirc

Sounds good. I was scared of by the name “Certified Full Stack Developer Curriculum” and thought I may as well start with something easy like HTML and than move on to JS and so on, not realizing that “Certified Full Stack Developer Curriculum” was also taught from scratch.
And thanks for your time.

1 Like