Typescript: Nullish coalescing operator (??)

Created on 21 Aug 2018  ·  29Comments  ·  Source: microsoft/TypeScript

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:

  • [x] This wouldn't be a breaking change in existing TypeScript / JavaScript code
  • [x] This wouldn't change the runtime behavior of existing JavaScript code
  • [x] This could be implemented without emitting different JS based on the types of the expressions
  • [x] This isn't a runtime feature (e.g. new expression-level syntax)
Committed Suggestion Update Docs on Next Release help wanted

Most helpful comment

Stage 3 now!

All 29 comments

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 .

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

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

@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.

Stage 3 now!

^^ source

You're welcome!

Could i take a try on this?

@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.

@DanielRosenwasser Okay, never mind

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

Stage 3 now!!!!

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

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

Is nullish coalescing also planned for TypeScript 3.7.0?

@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).

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

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.

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

@RyanCavanaugh: tsx/jsx

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!

@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!

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

@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.

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

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

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

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 && ?

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

Config.active will always be true after that, if it was a Boolean before

On Tue, Jun 2, 2020, 12:12 PM akopchinskiy notifications@github.com wrote:

@samterainsights https://github.com/samterainsights

config.name = config.name ?? "(no name)";
config.items = config.items ?? -1;
config.active = config.active ?? true;

Why not to use?

config.name = config.name || "(no name)";
config.items = config.items || -1;
config.active = config.active || true;


You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/microsoft/TypeScript/issues/26578#issuecomment-637656195,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/ADHFRL362X5K7NB7SFRQ2VLRUUQGVANCNFSM4FQX6DIA
.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Roam-Cooper picture Roam-Cooper  ·  3Comments

CyrusNajmabadi picture CyrusNajmabadi  ·  3Comments

MartynasZilinskas picture MartynasZilinskas  ·  3Comments

weswigham picture weswigham  ·  3Comments

DanielRosenwasser picture DanielRosenwasser  ·  3Comments