type PipeFn<T extends any[], R> = (...args: T) => R;
export function pipe<T extends any[], A>(fn1: PipeFn<T, A>): PipeFn<T, A>;
export function pipe<T extends any[], A, B>(fn1: PipeFn<T, A>, fn2: (a: A) => B): PipeFn<T, B>;
export function pipe<T extends any[], A, B, C>(fn1: PipeFn<T, A>, fn2: (a: A) => B, fn3: (b: B) => C): PipeFn<T, C>;
// Add more overloads as needed for additional functions in the pipeline
export function pipe(...fns: Function[]) {
return (...args: any[]) => fns.reduce((result, fn) => [fn(...result)], args)[0];
}
export const asyncPipe =
(...fns: ((value: any) => any)[]) =>
(initialValue: any) =>
fns.reduce((promise, fn) => promise.then(fn), Promise.resolve(initialValue));
위의 pipe 툴을 이용해서 함수들을 합성해본다. compose와 달리 pipe는 나의 직관과 일치하는데, 앞에서부터 차례로 실행하고, return 값을 뒤의 함수의 매개변수에 넣는다. 여기에서 좀 더 간결한 로직을 만들 수 있도록 앞에서 튜플 등의 자료구조를 배웠던 것이다 혹은 커리나, 부분 적용으로 더 쉽게 만들 수 있다. 어쨌든, 위의 pipe를 써서 직접 만들어본 로직은 이거였다. 하지만, 이건 위의 로직을 써보기 위해 좀 억지스럽게 만든 느낌이 좀 들긴한다.
const checkURLParams = ([type, id]: string[]) => {
if (type === ':type' || !type) {
return { action: 'redirect', route: 'home' };
} else if (id === ':id' || !id) {
return { action: 'redirect', route: 'template-list', params: { type } };
} else {
return { action: 'proceed', id };
}
};
const handleRouting = async (result: ReturnType<typeof checkURLParams>) => {
if (result.action === 'redirect') {
await router.push({
name: result.route,
...(result.params && { params: result.params }),
});
}
return result.id || '';
};
const initAPI = async (id: string) => {
try {
if (isValid(id)) {
const response = await template.getTemplate(id);
return response;
}
} catch (err) {
await router.push({ name: 'template-list' });
}
};
const initComponent = asyncPipe(checkURLParams, handleRouting, initAPI);
: 사실 위의 로직이 꼭 함수형으로 작성됐어야 하는건 아니고, 저 코드가 그렇게 깔끔해 보이지도 않는다. 요즘 뭔가 함수형 프로그래밍에 대해 배우고 나서 이걸 꼭 적용해야겠다라는 강박이 있어서 그런지 좀 안어울리는 코드가 양산(?)되고 있는 느낌도 있다. 그리고 아직 함수형에 적응을 제대로 못한 것도 맞는 것 같다. 따라서, 이제부터는 일단 프로젝트를 진행할 때는
위의 규칙만을 일단은 고려하면서 개발해보자. pipe, curry, partial, Either 등 배운 것을 써먹으려는 시도도 좋지만, 일단 함수형 프로그래밍의 기본인 부수효과가 없는 순수 함수들의 조합을 통한 관심사 분리 및 재사용성 증대의 측면에서 접근해보자. 그러면서 자연스럽게 위의 도구들이 생각나서 쓰도록 해보자. 모든 함수를 아토믹 패턴에서 atom의 정도로 쪼개서 쓰면서 역시 아토믹 패턴처럼 그 함수들을 조합해서 새로운 함수를 계속해서 생성하면서 써나간다 라는 것에 초점을 맞춰보자.