[SOLVED] What's the best way of dealing with optional and dynamic function parameters?

Issue

This is my function that generates and returns an array (Please see the comments in the code below):

const getStylesArray = (noteBlockSettings, blockId, key, value) => {

    // ---------------------------------------------------
    // noteBlockSettings parameter will be passed to this function no matter what. 
    // So it is definetely not undefined.

    // NoteBlockSettings has bgOpacity, bgColor, primaryColor, secondaryColor, textColor keys and values.

    // key and value parameters of this function are optional, so they may be undefined or not.

    // ***** What i am trying to achieve is : *****
    // If key parameter is passed (can be bgOpacity, bgColor, primaryColor, secondaryColor, textColor)
    // use this passed parameter rather than the value in noteBlockSettings object. 
    // If key parameter is undefined, use the value in noteBlockSettings object.
    
    // ---------------------------------------------------

    let { bgColor, primaryColor, secondaryColor, bgOpacity, textColor } = noteBlockSettings

    if (key === 'bgColor') {
         bgColor = value
    }

    if (key === 'primaryColor') {
         primaryColor = value
    }

    if (key === 'secondaryColor') {
         secondaryColor = value
    }

    if (key === 'bgOpacity') {
         bgOpacity = value
    }

    if (key === 'textColor') {
         textColor = value
    }


    const stylesArray = [
         // Here i am using the variables defined above to dynamically generate the array
         // Like bgOpacity, bgColor, primaryColor, secondaryColor, textColor etc..
         {
              styleClass: '.head',
              styleValue: `background:${addAlpha(colord(bgColor).lighten(0.075).toHex(), bgOpacity)}; border-color:${addAlpha(colord(bgColor).darken(0.06).toHex(), bgOpacity)};`,
              styleTriggers: 'bgColor bgOpacity',
         },

         {
              styleClass: '.head .options .btn-icon',
              styleValue: `color:${addAlpha(colord(textColor), 0.4)};`,
              styleTriggers: 'textColor',
         },

         {
              styleClass: '.head .options .btn-icon:hover',
              styleValue: `color:${primaryColor};`,
              styleTriggers: 'primaryColor',
         },
         .
         .
         .
    ]

    // Finally returning the generated array 
    return stylesArray
}

This is working and it is just a primitive attempt. However I don’t know how, but I feel like there should be much "smarter" way of handling this.

So, my question is: What is the best and minimal way of achieving the same result?

Solution

You can build a "final" settings object before destructuring it. Then you don’t need to check every variable:

// If `key` is passed and a valid key in the object, copy the object and overwrite
// the property. 
const finalSettings = key in noteBlockSettings ? 
   {...noteBlockSettings, [key]: value} :
   noteBockSettings;

const { bgColor, primaryColor, secondaryColor, bgOpacity, textColor } = finalSettings;
// ...

{...noteBlockSettings, [key]: value} basically copies noteBlockSettings and sets the property whose name is in key to value.

Having said that, I’m wondering why the call site simply doesn’t pass the complete settings object. That would make the API clearer.

Answered By – Felix Kling

Answer Checked By – David Goodson (BugsFixing Volunteer)

Leave a Reply

Your email address will not be published. Required fields are marked *