js나 react.js에서 유용하게 사용되는 map API를 알고 있다면
이를 직접 구현해보는 것이 가능할 것이다.
함수의 범용성을 위해 generic을 사용하는 typeScript의 map은
어떤 형태를 가질지 예상해보자.
function map<T>(array:T[], f:(item:T)=>T):T[]{
let result=[];
for( let i=0; i< array.length; i++){
result[i]=f(array[i])
}
return result;
}
generic이 아직 어색하다면 대략 이런 느낌의 코드를 생각할 수 있다.
하지만 이는 문제가 있는데
map은 기본적으로 함수를 받아 순회하며 각 index에 callback함수를
적용시킨 함수를 반환받는다.
그런데 위 map함수는 callback함수로 후처리가 끝난 후에도
입력 타입인 T타입을 그대로 사용하고 있다. 즉 반환값인 result가 T타입이라는 것이다.
예를 들어 이런 map함수는 위 코드에 적합하지 못하다.
function map<T>(array:T[], f:(item:T)=>T):T[]{
let result=[];
for( let i=0; i< array.length; i++){
result[i]=f(array[i])
}
return result;
}
const lap=map(['a','b','c'],_=>_==='a');
console.log('lap: ',lap)
하고싶은 말은 generic을 사용한 보람이 없다는 것이다.
해결책은 한 지붕에 두 generic을 사용하면 된다.
코드를 아래처럼 바꾸어보자
function map<T,U>(array:T[],f:(item:T)=>U):U[]{
let result=[];
for(let i=0;i<array.length;i++){
result[i]=f(array[i])
}
return result
}
문제 해결법은 하나의 generic을 멋지게 활용하는것이 아닌
하나의 generic 변수를 하나 더 쓰는 것이다.
callback함수를 통해 후처리 된 값은 T타입을 수 있고
다를 수 있다. 그렇다면 generic을 하나 더 쓰면 되는 것이다.
const lap=map(['a','b','c'],_=>_==='a');
console.log('lap: ',lap);
그 후에는 이렇게 배열을 만들어 반환해준다.
당연하게도 이름을 map으로 지어서 사용하면 안된다. shadowing을 유발하기 때문에 좋지 못한 작명이다.
아무튼 이렇게 generic을 두 개 사용하는 것에 대해 알아보았다.
무언가 막히면 하나를 더 써보는건 어떨지 생각해보자.