Skip to content
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

Nullish coalescing operator (??) #26578

Closed
4 tasks done
samclaus opened this issue Aug 21, 2018 · 29 comments · Fixed by #32883
Closed
4 tasks done

Nullish coalescing operator (??) #26578

samclaus opened this issue Aug 21, 2018 · 29 comments · Fixed by #32883
Labels
Committed The team has roadmapped this issue Help Wanted You can do this Suggestion An idea for TypeScript Update Docs on Next Release Indicates that this PR affects docs

Comments

@samclaus
Copy link

samclaus commented Aug 21, 2018

Search Terms

  • nullish coalescing

Suggestion

A nullish coalescing operator, which is essentially an alternative to || that will only return the right-side expression if the left-side is null or undefined (|| returns the right-side if the left-side is falsy, i.e. null | undefined | "" | 0 | false | NaN).

Use Cases

This would be extremely useful anywhere where defaults are needed for potentially omitted inputs, but empty strings or 0, and so forth, are valid inputs that shouldn't be defaulted. My particular use case is AngularJS component bindings. Whenever bindings are updated, I would like to provide a default for a string or boolean binding only when they are straight up omitted (undefined), but I have to do a full-fledged ternary expression with typeof to handle the falsy input corner-case.

In conjunction with the safe chaining operator (#16), handling optionals would be trivial.

Examples

export interface Configuration {
    // Default: "(no name)"; empty string IS valid
    name?:  string;

    // Default: -1; 0 is valid
    items?:  number;

    // Default: true
    active?: boolean;
}

function configureSomething(config: Configuration) {
    // With null-coalescing operator
    config.name = config.name ?? "(no name)";
    config.items = config.items ?? -1;
    config.active = config.active ?? true;

    // Current solution
    config.name = typeof config.name === "string" ? config.name : "(no name)";
    config.items = typeof config.items === "number" ? config.items : -1;
    config.active = typeof config.active === "boolean" ? config.active : true;

    // Using || operator (INCORRECT)
    config.name = config.name || "(no name)"; // does not allow for "" input
    config.items = config.items || -1; // does not allow for 0 input
    config.active = config.active || true; // really bad, always true
}

Checklist

My suggestion meets these guidelines:

  • This wouldn't be a breaking change in existing TypeScript / JavaScript code
  • This wouldn't change the runtime behavior of existing JavaScript code
  • This could be implemented without emitting different JS based on the types of the expressions
  • This isn't a runtime feature (e.g. new expression-level syntax)
@ghost
Copy link

ghost commented Aug 21, 2018

This isn't a runtime feature (e.g. new expression-level syntax)

This is new expression-level syntaxx. It's already a proposal for JS: https://github.com/tc39/proposal-nullish-coalescing .

@ghost ghost added the Out of Scope This idea sits outside of the TypeScript language design constraints label Aug 21, 2018
@RyanCavanaugh RyanCavanaugh added the Suggestion An idea for TypeScript label Aug 21, 2018
@jhpratt
Copy link

jhpratt commented Dec 9, 2018

@andy-ms Shouldn't the tag be waiting for TC39, not out of scope?

@MatthiasKunnen
Copy link

Nullish coalescing has reached stage 2. Can this issue be reopened or will this be addressed elsewhere?

@davidje13
Copy link

@MatthiasKunnen given the close connection, I'm guessing this will be brought in along with #16, but the general rule seems to be to wait for stage 3, so we have a bit longer to wait yet.

@RyanCavanaugh RyanCavanaugh added Waiting for TC39 Unactionable until TC39 reaches some conclusion and removed Out of Scope This idea sits outside of the TypeScript language design constraints labels Jul 15, 2019
@natew
Copy link

natew commented Jul 24, 2019

Stage 3 now!

@jhpratt
Copy link

jhpratt commented Jul 24, 2019

^^ source

@DanielRosenwasser
Copy link
Member

You're welcome!

@Kingwl
Copy link
Contributor

Kingwl commented Jul 24, 2019

Could i take a try on this?

@DanielRosenwasser
Copy link
Member

@rbuckton has an old branch that implements this (I would link you to it but it's searchable and I'm on mobile), so it depends on how bad the merge conflict would be and whether he would mind.

@Kingwl
Copy link
Contributor

Kingwl commented Jul 24, 2019

@DanielRosenwasser Okay, never mind

I found that branch and that is committed at 7 Oct 2017... seems a big work

@eos3tion
Copy link

Stage 3 now!!!!

@dragomirtitian
Copy link
Contributor

@DanielRosenwasser Can I try this? If @Kingwl is not still interested that is.

@Kingwl
Copy link
Contributor

Kingwl commented Jul 25, 2019

@dragomirtitian 🤷🏻‍♂️ Seems @rbuckton has nearly completely implemented that(without tests)

@MatthiasKunnen
Copy link

Is nullish coalescing also planned for TypeScript 3.7.0?

@jhpratt
Copy link

jhpratt commented Jul 25, 2019

@MatthiasKunnen Given that optional chaining (#16) is listed for 3.7.0, I presume these would land together (as the proposals go hand-in-hand).

@MatthiasKunnen
Copy link

@jhpratt, I'm aware of optional chaining's milestone but don't want to assume nullish coalescing's milestone. That's why I asked

@DanielRosenwasser DanielRosenwasser added Committed The team has roadmapped this issue and removed Waiting for TC39 Unactionable until TC39 reaches some conclusion labels Jul 26, 2019
@DanielRosenwasser DanielRosenwasser added this to the TypeScript 3.7.0 milestone Jul 26, 2019
@Duckers
Copy link

Duckers commented Aug 3, 2019

Pardon my ignorance, but what about the inverse case? Does an an issue/proposal for that exist? Or is there a trick to achieve this now using existing operators?

In my experience the inverse problem is perhaps even more common, where && erroneously returns left hand side:

{foo && <Something foo={foo} />

Will not display a Something of foo is falsy, including "" and 0.

@RyanCavanaugh
Copy link
Member

RyanCavanaugh commented Aug 4, 2019

🤔 foo?.toString && <Something foo={foo} />

@rbuckton
Copy link
Member

rbuckton commented Aug 4, 2019

@RyanCavanaugh: tsx/jsx

@RyanCavanaugh RyanCavanaugh added the Help Wanted You can do this label Aug 14, 2019
@RyanCavanaugh
Copy link
Member

Hey folks (in particular @Kingwl and @dragomirtitian) - we'd love to have this feature shipped as a headlining "community-implemented" feature in 3.7. I think whoever claims dibs first can put up a draft PR and then hopefully work with others to contribute fixes, finish things out, and add testcases.

@sheetalkamat will be helping coordinate and offer advice / code review throughout the process.

Thanks!

@dragomirtitian
Copy link
Contributor

@RyanCavanaugh Hey, I have a 6 day chunk of time free time starting tomorrow, so I can start on this right away.

@sheetalkamat Should I start from @rbuckton 's old branch? Or should I start from scratch?

Thanks!

@Kingwl
Copy link
Contributor

Kingwl commented Aug 14, 2019

@dragomirtitian
I already have a migrated branch, based @rbuckton commit (and a few changes). Could we work on it?🤔

@Kingwl Kingwl mentioned this issue Aug 14, 2019
11 tasks
@dragomirtitian
Copy link
Contributor

@Kingwl Hi, sure, I'd be happy to collaborate on what is already there. Are you on gitter ? Maybe we can sync there as to what work still needs to be done and how to divide it up.

@Kingwl
Copy link
Contributor

Kingwl commented Aug 14, 2019

@dragomirtitian Sure, Thanks
Fortunately, I'm at UTC+8 and you are at UTC+3😍

@nisimjoseph
Copy link

thank you so much on the feature!
I played with it a little and saw the TS 3.7-Beta generate extra parenthesis in the end result, see here:
https://www.typescriptlang.org/play/index.html?ts=3.7-Beta#code/JYOwLgpgTgZghgYwgAgKoGdrIN4FgBQyRycAJqVBOugPwBcR2yBxryCwYAng+mFKADmLNkQAOAez4BhCaQi9+QkUQC+BdfgLyEAGziV2EkH2QBXTFACMDDNG0Q9BlAmOmL0AEy3LBAsBhkAAoPa2QaGnNLTwBKHBVmfFUgA

@DanielRosenwasser
Copy link
Member

You're welcome! If you would like to suggest improvements, feel free to open another issue.

@the21st
Copy link

the21st commented Feb 18, 2020

What about the question raised by @Duckers ? I'm curious what's the recommended syntax there. Is there a plan to add safe coalescing operator to replace && ?

@samhh
Copy link

samhh commented Feb 18, 2020

@the21st This is a more appropriate question for TC39, perhaps here.

@dantonel
Copy link

dantonel commented Jun 2, 2020 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Committed The team has roadmapped this issue Help Wanted You can do this Suggestion An idea for TypeScript Update Docs on Next Release Indicates that this PR affects docs
Projects
None yet
Development

Successfully merging a pull request may close this issue.