제로쵸 : 타입을 사용하는것 뿐 아니라 타입을 만들줄도 알아야합니다!
타입을 단순하게 지정하고 사용하는 것이 아니라 타입을 만든다라는 개념이 좀 생소했다. 그래서 이번 제로쵸 강의가 크게 도움이 되었다. 오늘은 forEach를 통해서 타입을 생성하는 개념을 제로쵸 강의의 흐름대로 정리해보았다.
const a:Arr = [1,2,3]
a.forEach((item) => {
console.log(item);
})
이런 코드에서 Arr의 타입을 지정해보도록 하자. 거꾸로 파악한다는 뜻은 forEach에서 사용하는 타입을 거꾸로 추론하는 것이다. 저 식을 예로 들자면 forEach는 void함수이고 안에 들어가는 배열은 콜백함수로 이루어져있다. 고로, 이런식으로 추론할 수 있다.
interface Arr {
forEach(callback: (item:number)=> void):void
}
이제 forEach에서 string과 number 케이스 두 가지를 선택적으로 적용하는 방법에 대해 알아보도록 하자. 여기에서 선택적이라는 표현으로 우리는 제네릭을 사용해야 한다는 사실을 떠올려야 한다. 아래의 예시에서 a는 number, b는 string을 사용하는 함수이다
interface Arr {
forEach(callback: (item: string | number) => void): void;
}
const a:Arr = [1,2,3];
a.forEach((item) => {
console.log(item);
item.toFixed(1); //number에서만 가능
})
const b:Arr = ['1','2','3'];
b.forEach((item) => {
console.log(item);
item.charAt(1); //string에서만 가능
})
위 예시에서 a와 b를 둘 다 잡기 위해 string|number 타입을 사용하였으나 오히려 두 코드에서 동시에 오류가 발생하였다. 이 해결책은 사용하는 쪽에서 타입을 지정해주는 제네릭을 사용하는 것이다.
interface Solution<T> {
forEach(callback: (item: T) => void): void;
}
const c:Solution<number> = [1,2,3]
c.forEach((item) => {
console.log(item);
item.toFixed(1); //number에서만 가능
})
const d:Solution<string> = ['1','2','3'];
d.forEach((item) => {
console.log(item);
item.charAt(1); //string에서만 가능
})
위 코드에서는 Solution이라는 제네릭 메소드를 사용하여 item의 타입에 따라 가변적으로 바뀌게 생성하였다. 그 결과로 c와 d의 타입에서 안에 속한 함수를 자유롭게 사용할 수 있게 되었다.