📌 해당 글은 타입스크립트에서 제네릭에 관한 첫번째 내용이다. 제네릭의 기본 구문, 제네릭 함수 / 인터페이스에 대해 학습하고 정리해보았다.
제네릭(Generic)이란?
타입스크립트에서 제네릭이란, 타입 변수를 통해 함수 / 클래스 / 인터페이스 등에 '일반화'된 (특정 타입에 종속되지 않는) 정적 타입을 지정하는 기능이다.
function everythingReturn(arg: any): any {
return arg;
}
위 everythingReturn
함수는 any
타입의 매개변수를 받아 그대로 리턴하는 함수이다.
하지만 이렇게 함수를 선언하면 정적 타이핑을 하는 의미가 없고, 우리가 어떤 타입을 매개변수로 전달하던 any
타입만 리턴된다.
function everythingReturn<T>(arg: T): T {
return arg;
}
// 1. 타입 변수의 타입을 직접 전달
let result = everythingReturn<string>('string');
// 2. 타입 인수 추론을 통해 자동으로 지정된 타입 (가장 일반적)
let result = everythingReturn('string');
// let result : string
위 예제는 T
라는 타입 변수를 추가하여, 매개변수의 타입을 캡처하고 (담아둠), T
를 반환 타입에 다시 사용했다.
everythingReturn
함수는 위의 첫번째 예제처럼 특정 타입에 종속되지 않는다.
이처럼 any
타입을 사용하는 대신, 타입 변수를 통해 어떤 타입이 매개변수로 들어오던 유연하게 정적 타입을 지정할 수 있다.
만약, 제네릭 함수 내에서 매개변수 값의 길이를 콘솔에 출력하고 싶으면 어떻게 해야할까?
function loggingArgLength<T>(arg: T): T {
console.log(arg.length); // 오류: 'T' 형식에 'length' 속성이 없습니다.
return arg;
}
아마 이렇게 코드를 작성해야 할텐데, 함수 본문에서 오류가 나는 것을 볼 수 있다. 왜나햐면 어느 곳에서도 arg
매개변수에 length
속성이 있는지 지정되어 있지 않기 때문이다.
function loggingArgLength<T>(arg: T[]): T[] {
console.log(arg.length);
return arg;
}
위 예제처럼 어떤 타입의 배열을 받아, 해당 배열의 길이를 출력하는 함수였을 때를 가정해보자. 만약 number
타입의 배열이 매개변수로 넘어왔어도, 배열은 length
속성을 가지고 있기 때문에 오류가 발생하지 않는다.
이러한 상황에서 제네릭 타입 변수를 사용하면 정적 타이핑은 유지한 채, 코드에 유연함을 제공할 수 있을 것 같다.
함수 자체의 타입과 제네릭 인터페이스를 만드는 방법에 대해 알아보자.
function everythingReturn<T>(arg: T): T {
return arg;
}
const myEverythingReturn: <Val>(arg: Val) => Val = everythingReturn;
위 예제에서 myEverythingReturn
변수는, 함수 타입을 가지는 변수이다.
즉, everythingReturn
함수를 할당받아 해당 함수를 호출할 수 있는 참조이다.
// 1
interface GenericMyReturnFn {
<T>(arg: T): T;
}
// 2
interface GenericMyReturnFn<T> {
(arg: T): T;
}
// 1. 제네릭 함수를 정의한 인터페이스를 활용한 방식
const myEverythingReturn: GenericMyReturnFn = everythingReturn;
// 2. 제네릭 인터페이스 자체에 타입 매개변수를 지정하는 방식
const myEverythingReturn: GenericMyReturnFn<string> = everythingReturn;
또한, 위 예제처럼 제네릭 인터페이스를 작성할 수 있다. 제네릭 인터페이스를 선언하는 두 가지 방식이 있는데, 동작상에 큰 차이는 없다고 한다. 자신이 놓인 상황에서 적절히 선택하여 사용하면 좋을 것 같다.
개인적으로 두번째 방식이 명확하게 어떤 타입에 대한 동작을 작성하는지 쉽게 이해할 수 있어, 가독성 측면에서 더 좋아보인다.
이렇게 제네릭의 기본 개념과, 구문에 대하여 알아보았다.
글을 정리하며 이전 프로젝트들의 코드를 살펴보았는데, 제네릭을 활용한 부분이 거의 없었다. 이제 개념을 알았으니까 필요할 때 활용해봐야지..!
다음 글에서는 제네릭 클래스와 제약조건에 대해 알아보자 👍
참고 문서