Skip to main content
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Ben Michel
Ben Nadel at InVision In Real Life (IRL) 2019 (Phoenix, AZ) with: Ben Michel

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

By
Published in Comments (7)

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.

Want to use code from this post? Check out the license.

Reader Comments

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

15,841 Comments

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

15,841 Comments

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

I believe in love. I believe in compassion. I believe in human rights. I believe that we can afford to give more of these gifts to the world around us because it costs us nothing to be decent and kind and understanding. And, I want you to know that when you land on this site, you are accepted for who you are, no matter how you identify, what truths you live, or whatever kind of goofy shit makes you feel alive! Rock on with your bad self!
Ben Nadel