제네릭(Generic)은 C#과 Java와 같은 객체지향 프로그래밍에서 사용하는 기법입니다.
메서드 매개변수의 구체적인 타입을 기재하지 않고 다양한 타입을 처리할 수 있는 기술이며, 제네릭을 잘 사용한다면 코드의 재사용성을 높일 수 있습니다.
이러한 제네릭은 타입을 엄격하게 처리하는 TypeScript에서도 사용할 수 있으며, 함수, 인터페이스, 클래스의 재사용성을 높일 수 있습니다.
이번 포스팅에서는 타입스크립트에서 제네릭 기법을 사용하여 함수를 구현하는 방법에 대해 정리하였으며, 이론적으로 설명하기에는 한계가 있어서 코드 위주로 정리하였습니다.
제네릭(Genric)
다음은 매개변수를 그대로 반환하는 함수들입니다.
// number 타입의 매개변수를 return하는 함수
function NumberReturnFunc(arg: number): number {
return arg;
}
// string 타입의 매개변수를 return하는 함수
function StringReturnFunc(arg: string): string {
return arg;
}
// boolean 타입의 매개변수를 return하는 함수
function BooleanReturnFunc(arg: boolean): boolean {
return arg;
}
함수의 기능은 똑같은데, 매개변수의 타입과 반환하는 타입이 다르다는 이유로 여러 개의 함수를 구현하였습니다.
이러한 방식은 제네릭 기법을 사용하여 한 개의 함수로 구현할 수 있습니다.
function GenericReturnFunc<T>(arg: T): T {
return arg;
}
제네릭 함수 구현 방법은 함수명 뒤에 <T>를 추가하며, T를 매개변수의 타입 또는 반환 타입으로 설정할 수 있습니다.
꼭 <T>로 작성할 필요는 없으며, T 대신에 다른 문자열을 사용해도 됩니다.
(인터넷 또는 책에서 대부분 T로 작성하는 이유는 T가 Type의 약자이기 때문입니다.)
아래는 위에서 만든 제네릭 함수를 호출하는 코드입니다.
let numVar = GenericReturnFunc<number>(123);
let strVar = GenericReturnFunc<string>('ABC');
<> 안에는 인수의 타입을 작성합니다.
만약, 인수와 인수의 타입이 다를 경우 아래 사진처럼 경고문이 발생합니다.
<> 안에 작성한 타입과 제네릭 함수에 전달하는 인수의 타입이 일치한지 확인할 수 있습니다.
any 타입의 문제점
문제점 1. any 타입은 함수의 반환 타입을 유추하기 어려움
위에서 설명한 내용은 제네릭 함수를 사용하지 않고 아래 코드처럼 any 타입으로 매개변수의 타입과 함수의 반환 타입을 지정할 수 있습니다.
function AnyReturnFunc(arg: any): any {
return arg;
}
하지만, any 타입을 함수의 반환 타입으로 지정한 경우 무슨 값을 반환하는지 유추하기 어렵습니다.
// number 타입의 값인 123을 전달하였지만, 무슨 타입을 return 받는지 유추하기 어려움
let numVar = AnyReturnFunc(123);
// stirng 타입의 값인 ABC를 전달하였지만, 무슨 타입을 return 받는지 유추하기 어려움
let strVar = AnyReturnFunc('ABC');
함수의 반환 타입을 any로 명시하는 것보다 <> 안에 타입을 명시하여 무슨 타입으로 반환하는지 유추하기 쉬운 제네릭 함수를 사용하는 것이 유지보수 측면에서 좋습니다.
function GenericReturnFunc<T>(arg: T): T {
return arg;
}
let numVar = GenericReturnFunc<number>(123);
참고로 제네릭 함수를 호출할때, <> 안에 타입을 명시하는 것이 필수는 아닙니다. 아래 코드처럼 <>를 생략할 수 있는데요.
let strVar = GenericReturnFunc('ABC');
<>를 생략하는 경우 컴파일러가 인수의 타입을 보고 타입을 결정합니다.
'ABC'는 문자열(string)이므로 컴파일러는 인수의 타입이 문자열이므로 T는 string으로 결정합니다.
코드를 간결해주는 장점이 있지만, 타입을 유추하기 어려운 경우에는 <> 안에 타입을 명시하는 것이 좋습니다.
문제점 2. any 타입은 매개변수의 프로퍼티를 체크하지 않음
매개변수의 lentgh를 반환하는 코드입니다.
function AnyReturnFunc(arg: any): any {
return arg.length;
}
function GenericReturnFunc<Type>(arg: Type): Type {
return arg.length;
}
타입이 any인 코드는 경고가 없지만, 제네릭 함수는 사진처럼 경고가 발생합니다.
제네릭 함수는 무슨 타입이 올지 모르기 때문에 length 프로퍼티를 사용할 수 없습니다.
만약, any 타입으로 작성된 함수를 사용했을 경우 프로그램 실행 도중에 문제가 발생할 가능성이 많지만, 제네릭 타입을 사용하는 경우 사전에 문제가 되는 부분을 미리 방지할 수 있다는 장점이 있습니다.
제네릭 화살표 함수(Generic Arrow Function)
제네릭 화살표 함수를 아래 코드처럼 구현하는 경우 에러가 발생합니다.
let GenericReturnFunc = <Type>(arg: Type): Type => {
return arg;
}
.ts 확장자 파일에서는 정상적으로 동작할 수 있는데, .tsx 확장자 파일은 TypeScript + JSX로 구성되어 있어서 <Type>에서 태그(<>) 문제가 발생합니다.
.tsx 확장자 파일에서 제네릭 화살표 함수를 구현해야 하는 경우 제네릭 매개변수에 extneds를 사용하여 컴파일러에게 제네릭 화살표 함수라고 알려줘야 합니다.
let GenericReturnFunc = <Type extends {}>(arg: Type): Type => {
return arg;
}
'TypeScript' 카테고리의 다른 글
[TypeScript]타입스크립트 Property does not exists on type (0) | 2021.09.16 |
---|---|
[TypeScript]타입스크립트 게터(getter), 세터(setter) 구현 (0) | 2021.09.15 |
[TypeScript]타입스크립트 물음표(?), 선택적 프로퍼티, 옵셔널 체이닝 (0) | 2021.09.14 |
[TypeScript]객체(Object) 타입 정의 (1) | 2021.09.13 |
[TypeScript]타입스크립트 느낌표(!) 사용 (0) | 2021.09.13 |
댓글