Ben Nadel
On User Experience (UX) Design, JavaScript, ColdFusion, Node.js, Life, and Love.
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with: David Epler
Ben Nadel at cf.Objective() 2009 (Minneapolis, MN) with: David Epler@dcepler )

Using Guard Conditions To Short-Circuit Object-Spread Operations In TypeScript 3.2.4

By Ben Nadel on

After my post yesterday on applying the Object-Spread operator to Null and Undefined values in TypeScript, Duncan Bay showed me another cool feature of the Object-Spread operator: you can use guard conditions to short-circuit spread operations. Off the top of my head, I don't have a great use-case for this; but, I thought it was an idea worth sharing.

To see this in action, I'm going to create a new object into which I randomly spread two other objects:

  • interface StringMap {
  • [ key: string ]: string;
  • }
  •  
  • var target: StringMap = { a: "1" };
  • var value1: StringMap = { b: "2" };
  • var value2: StringMap = { c: "3" };
  •  
  • var clone: StringMap = {
  • ...target,
  •  
  • // This is a silly example; but, it's demonstrating that the Object-Spread operator
  • // can use Boolean guard-conditions in order to short-circuit the individual spread
  • // actions: we are randomly executing the spread of the two other values.
  • ...( ( Math.random() < .5 ) && value1 ),
  • ...( ( Math.random() < .5 ) && value2 )
  • };
  •  
  • console.log( "Clone:", clone );

As you can see, I'm using the following generalized concept:

...( truthy && spreadable )

When the "truthy" value is True, the expression returns "spreadable", which is then spread into the new structure. However, when the "truthy" is False, the expression returns the "falsey" value, which TypeScript quietly ignores as a non-spreadable value, which is essentially what we were seeing the last post (that Null and Undefined values were quietly ignored).

Now, if we run the above code, we get the following console output:


 
 
 

 
 Using guard conditions in the object-spread operator in TypeScript 3.2.4. 
 
 
 

Pretty cool stuff! As you can see, every time we run the ts-node file, we get a randomly-spread result. If these conditions had meaningful variable names, instead of Math.random() calls, I think it would lead to rather elegant, very readable logic.



Reader Comments

This is great, I had no idea "falsey" objects could be not-spread! Very elegant, inline solution ... whereas other "conditional" approaches are always really ugly!

I've done something similar with Array spread before. It was nice to have this logic inline, but it's ugly, because of the false-condition:

    plugins: [
        Plugin1,
        Plugin2,
        ...(USE_PLUGIN ? [ Plugin3 ] : []),
        Plugin4
    ]

So I'm going to experiment to see if Array-spread exhibits the same falsey-behavior, which would clean this up a bit!

Reply to this Comment

@Scott,

I haven't tested this myself, but I've read that Array-spread is more strict. I think the difference (as I've read) is that Array-spread is more about the "Iterable Interface" where as the Object-spread is more about feature-parity with Object.assign(), which I suppose is a lot more forgiving.

But, like I said, I haven't tested myself.

Reply to this Comment

@Artem,

Oh yeah, this is one of my favorite features of JavaScript! This type of behavior works with both the && and the || operator, but in slightly different ways. At the core, both operators return the last evaluated value.

So, with the && operator, the last evaluated value is the last one that evaluated to "true"; or, the first one that evaluated to "false":

1 && "hello"; // ===> "hello" - last evaluated True value.

1 && "" && "foo"; // ===> "" - first False value.

The expression will return the first False value because && "short-circuits" the expression. Meaning, once the runtime hits the Falsey value, it knows that it doesn't have to evaluate the rest of the operands as the overall expression will never be "True" at that point.

With the ||, its the same idea:

1 || "blam"; // ===> 1 - first True value.

0 || false || null; // ===> null - last False value.

The || operator is particularly helpful for ensuring default values:

function doit( a ) {
	a = a || "my default value";
}

Here, you are using a, unless it evaluates to a Falsey value, in which case you are using "my default value" as the fallback.

Hope you found this interesting.

Reply to this Comment

Post A Comment

You — Get Out Of My Dreams, Get Into My Comments
Live in the Now
Oops!
NEW: Some basic markdown formatting is now supported: bold, italic, blockquotes, lists, fenced code-blocks. Read more about markdown syntax »
Comment Etiquette: Please do not post spam. Please keep the comments on-topic. Please do not post unrelated questions or large chunks of code. And, above all, please be nice to each other - we're trying to have a good conversation here.