How do you implement the options object pattern in typescript?

Viewed 401

I'm going to answer my own question here because this is pretty difficult to Google and I want it to be easier for everyone to find.

This article explains what this pattern is:

An “options object” is a programming pattern that you can use to pass any number of named arguments to a function. Rather than using an ordered list of arguments, you simply pass one argument, which is an object containing named keys for all of your options. Keep reading to learn how and why.

You can use typescript features to implement this pattern in a more concise way. See my answer for how.

You can see a similar question about JavaScript here: Implement JavaScript options object parameter pattern?

This question is different because it's about JavaScript. There happens to be an answer on that JavaScript question that explains how to do it the typescript way, but I find it difficult to read because there's so much syntax punctuation.

2 Answers

Here's a link to code you can play around with.

    interface Options {
      lastSeparator?: string;
      separatorBetweenArrayOfTwo?: string;
      wrap?: (word: string) => string;
    }
    
    const separatedMessage = (
      words: string[],
      separator: string,
      { 
        lastSeparator = separator, 
        separatorBetweenArrayOfTwo = lastSeparator, 
        wrap = (word: string): string => {
          return word.toString();
        }
       }: Options = {} // the = {} at the end means you don't have to pass in an Object here if you don't want.
    ): string => {
      let buf = '';
    
      words.forEach((word, index, array) => {
        if (index !== 0) {
          if (array.length === 2) {
            buf += separatorBetweenArrayOfTwo;
          } else if (index === array.length - 1) {
            buf += lastSeparator;
          } else {
            buf += separator;
          }
        }
          buf += wrap(word);    
      });
      return buf;
    };
    
    console.log(separatedMessage(["a", "b", "c", "d"], ", "))
    console.log(separatedMessage(["a", "b"], ", ", {}))
    console.log(separatedMessage(["a", "b"], ", ", {lastSeparator: ", and "}))
    console.log(separatedMessage(["a", "b"], ", ", {lastSeparator: ", and ", separatorBetweenArrayOfTwo: " and "}))

This is how, using destructuring, you can use the options object pattern and typescript. This function lets you pass in an array of words, and separates them with characters. You can optionally specify the last separator -- to achieve "a, b, c, and d" -- optionally specify a separator between arrays of two -- to achieve "a and b" or "a, b, c, and d" depending on what you pass in -- and optionally pass in a function that wraps each word in something -- to achieve "'a', 'b', 'c', and 'd'".

We can define specific key-value pair or any for interface, then destructing the values.

interface Person {
    name: string;
    age: number;
    gender: string;
    hobby?: string;
    [key: string]: any;
}

function logPerson(person: Person) {
    console.log(person);
    return person;
}

function logPerson1(person: { [key: string]: any }) {
    console.log(person);
}

console.clear();
logPerson({ name: 'Kevin', age: 33, gender: 'male', hobby: 'basketball', hah: 'Hah' });
logPerson1({ name: 'Lucy', age: 100, gender: 'female', extra: 'extra property' });

Related