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);
}
};
먼저 Array.prototype에 새로운 두 메쏘드, asyncFilter와 asyncForEach를 추가해줍니다.
callback 인자는 이제 promise이기 때문에 Promise.all과 await을 사용할 수 있습니다.
하지만 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>;
}
본문에서는 filter
와 forEach
만 추가했지만 map
이나 reduce
도 같은 방식으로 할 수 있습니다.
이제 asyncFilter
나 asyncForEach
가 필요한 파일에 우리가 만든 ArrayExt.ts
파일을 import 해주기만 하면 됩니다.
import "./ArrayExt"
// .asyncFilter, .asyncForEach가 추가되었습니다!
this는 예약어라서 formal parameter 이름으로 사용할 수 없을 텐데 타입스크립트에서는 가능한건가요?
prototype에 추가하는 함수니까 굳이 this를 parameter로 받지 않아도 동작할 거 같습니다