Node.js의 forEach 혹은 filter는 동기적으로 동작합니다.

그렇기 때문에 async function과 함께 동작하게 만들려면 약간의 트릭이 필요한데요.

아래와 같은 식으로 할 수 있습니다.

// ArrayExt.ts
Array.prototype.asyncFilter = async function(callback) {
    const fail = Symbol();
    return (await Promise.all(
        this.map(async (item) => ((await callback(item)) ? item : fail)),
    )).filter((i) => i !== fail);
};

Array.prototype.asyncForEach = async function(callback) {
    for (let index = 0; index < this.length; index++) {
        await callback(this[index], index, this);
    }
};
  1. 먼저 Array.prototype에 새로운 두 메쏘드, asyncFilter와 asyncForEach를 추가해줍니다.

  2. callback 인자는 이제 promise이기 때문에 Promise.all과 await을 사용할 수 있습니다.

  3. 하지만 prototype만 추가하면 typescript 컴파일러가 아래와 같이 불평을 합니다.

Property 'asyncFilter' does not exist on type 'any[]'.

즉, Array 타입에는 asyncFilter라는 프로퍼티가 없다는 것이죠.

이 경우에는 위의 두 메쏘드에 대한 인터페이스를 정의해줘야합니다.

interface Array<T> {
    asyncFilter(
        callback: (element: T, index?: number, array?: T[]) => Promise<boolean>,
    ): Promise<T[]>;

    asyncForEach(
        callback: (element: T, index?: number, array?: T[]) => Promise<void>,
    ): Promise<void>;
}

본문에서는 filterforEach만 추가했지만 map이나 reduce도 같은 방식으로 할 수 있습니다.

이제 asyncFilterasyncForEach가 필요한 파일에 우리가 만든 ArrayExt.ts 파일을 import 해주기만 하면 됩니다.

import "./ArrayExt"

// .asyncFilter, .asyncForEach가 추가되었습니다!