Closed5
Array.prototype.flatMap と async/await の組み合わせが flatArray にならない
まんまハマりそうだった
Prismaに渡すデータを作成中
const UserCreateInputs = users.flatMap(async (user) => {
if (user.status.eq("DEACTIVATED")) return []
const data = await fetchDataFromAnotherService(user.id)
return [{
id: data.uid,
email: user.email,
}]
})
// 期待
// { id: string; email: string }[]
// 結果
// Promise<{ id: string; email: string }[]>[]
こんな感じになってた。flatMap最強説だったんだけど、これは仕方ない。
対策案その1
const work1 = await Promise.all(UserCreateInputs)
// 結果
// { id: string; email: string }[][]
const work2 = work1.flat()
// 結果
// { id: string; email: string }[]
何してるかわかりづらそうなので、asyncFlatMapを素直に作ると良いかも
async function asyncFlatMap<T, U>(
array: T[],
callback: (item: T) => Promise<U>,
) {
const promises = array.flatMap(callback);
const nestedResults = await Promise.all(promises);
return nestedResults.flat();
}
// test
const expected = await asyncFlatMap(users, async (user) => {
if (user.status.eq("DEACTIVATED")) return []
const data = await fetchDataFromAnotherService(user.id)
return [{
id: data.uid,
email: user.email,
}]
})
// 結果
// { id: string; email: string }[]
ほぼ同じですが、自分はこう書いたのでなんとなく共有させてください
異なる点は
-
promises
はflatMap
である必要はないので、ただのmap
にする -
callback
の引数にはflatMap
の仕様通りに全て渡す - arrow 関数で統一する
export const asyncFlatMap = async <Item, Res>(
arr: Item[],
callback: (value: Item, index: number, array: Item[]) => Promise<Res>
) => {
const a = await Promise.all(arr.map(callback));
return a.flat();
};
3点とも完全同意です。共有ありがとうございました!
このスクラップは2022/01/25にクローズされました