0

Given the scenario that I am working on a form, and I have this validation object

const errors = {
  username: ['minLength', Promise<string>, Promise<string>],
  password: [Promise<string>, Promise<string>]
}
// I need to convert the object to below
const errors = {
  username: ['minLength', string, string],
  password: [string, string]
}

The promise will all be resolved in the future so I came across this idea:

;(async function () {
    for (const key in errors) {
      if (errors.hasOwnProperty(key)) {
        errors[key] = (await Promise.all(errors[key])).filter(Boolean)
      }
    }
    callback(errors)
  })()

Is there a more functional way to do this?

// So far I know the most elegant way to map an object
// But won't work in this scenario
const newObj = Object.fromEntries(
  Object.entries(obj).map(([k, v]) => [k, v * v]),
)
crazyones110
  • 296
  • 3
  • 18
  • 1
    I think there are not many options here. Here is a comprehensive site about this: https://advancedweb.hu/how-to-use-async-functions-with-array-map-in-javascript/ – Gazihan Alankus May 27 '20 at 10:11

2 Answers2

3

You can throw in a Promise.all to make this work:

Promise.all(Object.entries(obj).map(([key, values]) =>
  Promise.all(values).then(results => [key, results.filter(Boolean)])
).then(Object.fromEntries).then(errors => {
  console.log(errors);
})

or, with async/await:

console.log(Object.fromEntries(
  await Promise.all(Object.entries(obj).map(async ([key, values]) =>
    [key, (await Promise.all(values)).filter(Boolean)]
  ))
))

And you definitely should - the code that loops over promises and awaits them one after the other is broken.

Bergi
  • 630,263
  • 148
  • 957
  • 1,375
0

There is a simple and functional way to do this using a library I wrote: rubico.

const { fork } = require('rubico')

const getErrors = fork({
  username: fork([
    () => 'minLength',
    () => Promise<string>,
    () => Promise<string>,
  ]),
  password: fork([
    () => Promise<string>,
    () => Promise<string>,
  ]),
})

const errors = await getErrors() /* => {
  username: ['minLength', string, string],
  password: [string, string],
} */

fork parallelizes promises that are the result of calling each supplied function with the input. There is no input in this case. I recommend supplying the functions that return those Promises in fork instead of supplying the Promises directly as I have done.

richytong
  • 2,387
  • 1
  • 10
  • 21