Search code examples
javascripttypescriptshort-circuit-evaluation

Shorthand Shortcircut. Is it possible to do some stuff


This question is about a TypeScript code-base, but the general concepts that underpin it are ECMAScript concepts, therefore; I have tagged the question as both JS & TS. If I should tag it differently, you can either let me know, or make the edit yourself and I will accept it if I see it.

In a TypeScript document, I have defined an object-type that contains 4 string typed properties.

Here is an example of the type
    type StrObjType = {
        foo?: string;
        boo?: string;
        fuz?: string;
        buz?: string;
    }

Along with the object described above, I have a function — its called funkyFunc — with a parameter that takes an argument of type StrObjType.


This is what the function looks like:
    function funkyFunc(obj:StrObjType)
    {
        let mesg = '';
        
        if(obj.foo){ mesg += '\n Foo: ' + obj.foo; }
        if(obj.boo){ mesg += '\n Boo: ' + obj.boo; }
        if(obj.fuz){ mesg += '\n Fuz: ' + obj.fuz; }
        if(obj.buz){ mesg += '\n Buz: ' + obj.buz; }
        
        if(!mesg) return '';

        // If a string was concatenated to mesg, return w/ newline appended
        return mesg + '\n';
    }

About the Function


If you can't tell by looking at it, the function creates a list using only properties that were added to the functions object-argument. The new-lines ('\n') are added as a means to format the list.

You can see in the function that each property in the object's type is checked for a truthy value. When a property is truthy, the props string-value is appended to the mesg variable via the "Addition Assignment Operator".


About the Problem & Solution


What I'd like to know, is if there is a better way to write the if statements, if I can short circuit them, or use a shorthand. Here is an example of a short circuit that uses nullish coalescing. The link shows a short circuit used to check an objects property, and assign it, only if the property is non-nullish (null or undefined). I was hoping to use that operator, but becauese I am appending the value when the property exist, rather than assigning it, the nullish coalescing won't seem to work. Nevertheless, I can't help but to feel like this is the ideal situation for implementing a short circuit, but if there is a better way to write the function, I can't figure out what it is.

There is this way of writing it, but IDK if it's better.

        let mesg = '';

        mesg += obj.foo ? '\n Foo: ' + obj.foo : undefined;
        mesg += obj.boo ? '\n Boo: ' + obj.boo : undefined;
        mesg += obj.fuz ? '\n Fuz: ' + obj.fuz : undefined;
        mesg += obj.buz ? '\n Buz: ' + obj.buz : undefined;

        if (!mesg) return '';

        return mesg + '\n';
    }

The problem with the above method of writing the function is that it requires using the JS built-in undefined constant, and that feels hacky to me, as the undefined constant wouldn't be needed otherwise. I could replace the undefined constant with an empty string I guess, but it still doesn't feel right, as it requires adding a nullish value, which are values I typically try to avoid (not that I see any immediate harm that comes from using undefined, or '').


So I guess my question is this...

Is there a shorthand, or short-circuit I can use to eliminate the if keywords in the first function example I added? The short circuit or shorthand cannot be the ternary example I already provided, and it needs to shorten the codes length, or improve the codes readability.



If there is any confusion, or if the question just isn't making sense, let me know, I will clear things up. I am peer reviewed, and I feel like there is something I am missing here. I would like to feel more confident about how I am authoring this function.


Solution

  • There is this way of writing it, but IDK if it's better.

    What you have after the text above will result in the string "undfined" appearing in mesg, which I assume you don't want. :-) If you wanted to do it that way, you'd use "", not undefined, for the third operand of the conditional operators:

    mesg += obj.foo ? "\n Foo: " + obj.foo : "";
    mesg += obj.boo ? "\n Boo: " + obj.boo : "";
    mesg += obj.fuz ? "\n Fuz: " + obj.fuz : "";
    mesg += obj.buz ? "\n Buz: " + obj.buz : "";
    

    What I'd like to know, is if there is a better way to write the if statements, if I can short circuit them, or use a shorthand.

    Not really. Moreover, what you have with the if statements (or the series of conditional operator expressions) is clear and easy to debug. There are other ways to do it, but they may be harder for people coming to the code fresh to understand.

    For example, you could have this constant:

    const messageParts = [
        {key: "foo", label: "Foo"},
        {key: "boo", label: "Boo"},
        {key: "fuz", label: "Fuz"},
        {key: "buz", label: "Buz"},
    ] as const;
    

    (The as const is important, that way TypeScript can see that the key values are valid keys for StrObjType.)

    Then the code is something like:

    for (const {key, label} of messageParts) {
        const value = obj[key];
        if (value) {
            mesg += `\n ${label}: ${value}`;
        }
    }
    

    Playground link

    For a one-off, that's definitely not an improvement, and it's certainly not short-circuiting or shorthand. But if there are a lot of places you use this same information, it gives you just one place to maintain it.

    But if it's a one-off just to build mesg, I think you're best off with the ifs you already have, or the conditional operator expression alternative you noted (with the undefined => "" fix).