Can a JS function know has many destructed variables are requested?

Let’s say I have a function that returns an array of a certain number of unique objects:

function getObjects() {
   const object = { lorem: 1 };
   return [{ ...object }];
}

If I wanted one of those objects, I would use a destructuring assignment like so:

const [first] = getObjects();

If I wanted two of those objects, I would attempt this:

const [first, second] = getObjects();

However, obviously the second is undefined. I could either pass in a parameter to the function of the number of objects I’m expecting:

function getObjects(length) {
   const object = { lorem: 1 };
   return Array.from({ length }).fill({ ...object });
}

Or I could just make the number of array items returned by getObjects so big that it would never reasonably fail. However neither of these solutions seem elegant, and I was wondering if there was a way that the getObjects function could know if the destructuring assignment is expecting 1, 2, or n number of objects.

Or if there is a completely different way to achieve the same result.

My specific use case is Storybook stories. I’m trying to think of a succinct way to clone a bunch of stories, without having something like this:

const Default = bindStory(Template);
const WithError = bindStory(Template);
const AnotherOne = bindStory(Template);

Where bindStory is returning a story object, that then has .args applied to it. Some of the files have 20, 30, stories in them. I was wondering if there would be a way to define it like this:

const [Default, WithError, AnotherOne] = bindStories(Template);

And then apply the .args to those individual objects.

>Solution :

To do this you can make use of infinite iterators. Destructuring assignment works on any iterable and so an infinite iterator allows for as many objects as you like. This means you don’t need to pass length and the variables will never be undefined.

function getObjects() {
  const object = {
    lorem: 1
  };
  return (function*() {
    while (true) {
      yield { ...object };
    }
  })();
};

const [first, second, third, fourth] = getObjects();
console.log({
  first,
  second,
  third,
  fourth
});

Leave a Reply