Generic에 대해서
TypeScript의 Generic문법에 대해서 공부하고 기록합니다.
개요 - 타입스크립트를 공부하면서 두려움에 떨다
자바스크립트를 처음 배울 때도 그랬지만, 새로운 언어를 배우는 과정은 항상 두려움과 불안으로 가득합니다.
타입스크립트를 처음 접했을 때도 마찬가지였습니다. 새로운 개념들을 이해하고 적용하는 과정에서 느끼는 막연한 두려움은, 마치 끝이 없는 미로 속을 걷는 기분이었습니다.
하지만 그 두려움을 극복하고 한 발자국씩 나아가다 보면, 그 과정에서 얻는 성취감은 이루 말할 수 없습니다.
타입스크립트를 처음 접했을 때, 특히 제네릭(Generic)이라는 개념이 저를 당혹스럽게 했습니다.
이론적으로는 어느 정도 이해했지만, 실제로 어떻게 활용해야 할지 감이 잡히지 않았습니다.
하지만 최근 팀 프로젝트에서 타입스크립트를 꼭 사용해야 하는 상황에 놓이면서, 제네릭을 포함한 타입스크립트의 다양한 기능들을 이해하고 활용할 수밖에 없었습니다.
결국, 시행착오 끝에 조금씩 타입스크립트를 이해하게 되었고, 지금은 제네릭의 필요성과 그 유용성에 대해 어느 정도 알게 되었습니다.
제네릭을 왜 쓰는가?
타입스크립트에서 제네릭은 다양한 타입을 다룰 때 매우 유용한 도구입니다. 제네릭을 사용하면 코드의 재사용성을 높이고, 타입 안정성을 유지하면서도 유연하게 코드를 작성할 수 있습니다.
예를 들어, 다음과 같은 함수가 있다고 가정해 봅시다.
function text(item) {
console.log(item);
return item;
}
text("하이");
text(120);
text(true);
이 함수는 item
이라는 인자를 받아 콘솔에 출력하고, 그 값을 반환합니다.
여기서 item
의 타입은 암묵적으로 any
로 취급됩니다. 따라서 이 함수는 string
, number
, boolean
타입의 값을 모두 처리할 수 있습니다.
그러나 any
타입은 타입스크립트의 강력한 타입 안전성을 무너뜨릴 수 있습니다.
이 함수를 string 타입만 처리하도록 제한한다면, 아래와 같이 작성할 수 있습니다.
function text(item: string) {
item.split("").reverse("").join("");
console.log(item);
return item;
}
text("하이"); // 실행 OK
text(120); // 에러
text(true); // 에러
이렇게 하면 함수는 string
타입의 값만 받을 수 있게 됩니다.
하지만 만약 number 타입도 처리해야 한다면, 새로운 함수를 만들어야 하는 불편함이 생깁니다.
이를 해결하기 위해 우리는 유니온 타입을 사용할 수 있습니다.
function text(item: string | number) {
console.log(item);
return item;
}
text(2323);
text("유니온타입");
유니온 타입은 여러 타입을 받을 수 있게 해주지만, 문제는 타입스크립트가 이 경우 공통된 메서드나 속성에만 접근할 수 있게 한다는 점입니다.
예를 들어, 아래와 같은 상황이 발생할 수 있습니다.
function text(item: string | number) {
console.log(item);
return item;
}
const a = text("유니온");
a.split(""); // 에러
이 코드는 split()
메서드가 string
타입에만 존재하기 때문에 타입스크립트는 오류를 발생시킵니다.
이런 문제를 해결하기 위해 등장한 것이 바로 제네릭입니다.
제네릭 사용방법
제네릭을 사용하면 함수가 받을 타입을 나중에 결정할 수 있습니다. 예를 들어, 다음과 같이 제네릭을 사용할 수 있습니다.
function text<T>(item: T): T {
console.log(item);
return item;
}
text<string>("나 제네릭 응애");
text<boolean>(false);
text<number>(223);
여기서 T
는 타입의 자리표(T)로, 함수가 호출될 때 그 타입이 결정됩니다. 예를 들어 text<string>("나 제네릭 응애")
를 호출하면, T
는 string
타입으로 변환되며, 함수는 string
타입의 값을 처리하게 됩니다.
제네릭의 강력한 점은 이렇게 호출 시점에 타입을 지정할 수 있다는 것입니다. 이를 통해 코드의 유연성과 재사용성을 높일 수 있습니다.
제네릭의 실제 활용 예시
타입스크립트의 기본 라이브러리에서도 제네릭이 널리 사용됩니다.
예를 들어, Array 타입은 제네릭을 사용하여 다양한 타입의 배열을 정의할 수 있습니다.
let stringArray: Array<string> = ["apple", "banana", "cherry"];
let numberArray: Array<number> = [1, 2, 3, 4];
또한, Promise도 제네릭을 활용하여 비동기 작업의 결과 타입을 지정할 수 있습니다.
function fetchData(): Promise<string> {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("데이터를 가져왔습니다!");
}, 1000);
});
}
fetchData().then((data) => {
console.log(data); // 타입스크립트는 data가 string 타입임을 알고 있음
});
결론: 제네릭, 두려움을 극복하고 얻은 성취
처음 제네릭을 접했을 때는 막연한 두려움이 있었지만, 결국 그 두려움을 극복하고 나니 타입스크립트의 강력한 도구를 하나 더 익히게 되었습니다.
제네릭은 다양한 타입을 안전하게 처리하고, 코드의 유연성을 높이는 데 큰 도움을 줍니다.
아직 마스터하지 못한 부분도 많지만, 타입스크립트를 더 깊이 이해하고 활용할 수 있게 되었다는 점에서 큰 성취감을 느낍니다.
앞으로도 계속해서 학습을 이어가며, 타입스크립트의 더 깊은 부분을 탐구하고, 실제 프로젝트에서 더 효율적으로 활용할 수 있도록 노력할 것입니다.