TypeScript

[TypeScript] Generics

lheunoia 2021. 12. 22. 16:21

 

 

 

 

재사용 가능한 컴포넌트를 작성하는 것은 소프트웨어 엔지니어링에서의 중요한 부분입니다. 이러한 재사용 가능한 컴포넌트를 생성하는 주요 도구 중 하나가 바로 제네릭입니다. 제네릭을 사용해서 함수를 생성하는 경우와 그렇지 않은 경우, 어떤 점이 다른지 알아 봅시다. 

 

 

 

 

 

🤯 제네릭을 사용하지 않는 경우

 

1. string 타입의 인자만 받을 수 있는 함수

function getText(text: string): string {
	return text;
}

 

getText 함수는 string 타입의 text만 받을 수 있습니다. 그런데 만약 getText 함수에 string 타입을 제외한 타입의 text를 넘긴다면 어떻게 될까요?

 

 

 

 

function getText(text: string): string {
	return text;
}

// error: Argument of type 'number' is not assignable to parameter of type 'string'.
getText(123);

 

number 타입의 인자를 string 타입의 파라미터에 할당할 수 없다는 에러가 나네요. 만일 getText 함수가 string 타입 이외의 타입 변수를 받지 않는다면 위 코드처럼 작성해도 문제는 없습니다. 그러나 함수가 한 가지 타입 변수만 받을지 불분명하고, 재사용 가능한 함수를 생성해야 한다면 위 같은 코드는 좋지 않습니다.

 

 

 

 

 

2. any 타입으로 인자를 받는 함수

function getText(arg: text): any {
	return text;
}

 

만약 여러 가지 타입을 허용하고 싶다면 위와 같이 any 사용할 수 있습니다. any를 쓰면 함수의 동작에 문제가 생기진 않지만, 함수의 인자로 어떤 타입이 들어갔고 어떤 값이 반환되는지는 알 수 없습니다. 왜냐하면 any라는 타입은 타입 검사를 하지 않기 때문입니다.

 

 

 

이러한 문제점을 해결할 수 있는 것이 제네릭입니다.

 

 

 

 

 

🤗 제네릭 사용하기

 

1. 제네릭 기본 문법

제네릭은 단일 타입이 아닌 다양한 타입에서 작동하는 컴포넌트를 작성할 수 있습니다.

 

function getText<T>(text: T): T {
	return text;
}

 

함수의 이름 바로 뒤에 <T>라는 코드를 추가하고 함수의 인자와 반환 값에도 T 라는 타입을 추가합니다. 이렇게 작성하면 함수를 호출할 때 넘긴 타입에 대해 타입스크립트가 추정할 수 있게 됩니다. 따라서, 합수의 입력 값에 대한 타입과 출력 값에 대한 타입이 동일한지 검증할 수 있게 됩니다.

 

 

 

그리고 이렇게 선언한 함수는 아래와 같이 2가지 방법으로 호출할 수 있습니다.

 

// #1
const text = getText<string>("Hello Generic");
// #2
const text = getText("Hello Generic");

 

보통 두 번째 방법이 코드도 더 짧고 가독성이 좋기 때문에 흔히 사용되는데요. 만약 복잡한 코드에서 두 번째 코드로 타입 추정이 되지 않는다면 첫 번째 방법을 사용하면 됩니다.

 

 

 

 

2. 제네릭 타입 변수

 

function getText<T>(text: T): T {
	return text;
}

 

만약 여기서 함수의 인자로 받은 값의 length를 확인하고 싶다면 어떻게 해야 할까요? 

 

 

 

 

function getText<T>(text: T): T {
	console.log(text.length); // error: T doesn't have .length
	return text;
}

 

위 코드를 변환하려고 하면 컴파일러에서 에러를 발생시킵니다. 어디에도 text 인자에 length가 있다는 단서는 없기 때문이죠. 제네릭은 함수의 인자와 반환 값 타입에 마치 any를 지정한 것과 같은 동작을 하기 때문에, 인자에 number 타입을 넘기더라도 에러가 발생하지는 않습니다. 이러한 특성 때문에 text에 문자열이나 배열이 들어와도 아직은 컴파일러 입장에서 length를 허용할 수 없습니다.

 

 

 

 

이런 경우에는 아래와 같이 제네릭에 타입을 줄 수 있습니다.

 

function getText<T>(text: T[]): T[] {
	console.log(text.length); // 3
	return text;
}

getText([1, 2, 3]);

 

제네릭 함수 코드는 T라는 변수 타입을 받고, 인자 값으로는 배열 형태의 T를 받습니다. 이제는 getText 함수에 [1, 2, 3] 처럼 숫자로 이루어진 배열을 넘기면 length를 참조할 수 있게 됩니다.

 

 

 

 

 

 

 

 

 

 

 

 

 

참고 자료

https://joshua1988.github.io/ts/guide/generics.html#%EC%A0%9C%EB%84%A4%EB%A6%AD-%ED%83%80%EC%9E%85-%EB%B3%80%EC%88%98

 

제네릭 | 타입스크립트 핸드북

제네릭(Generics)의 사전적 정의 제네릭은 C#, Java 등의 언어에서 재사용성이 높은 컴포넌트를 만들 때 자주 활용되는 특징입니다. 특히, 한가지 타입보다 여러 가지 타입에서 동작하는 컴포넌트를

joshua1988.github.io

 

반응형

'TypeScript' 카테고리의 다른 글

[TypeScript] type vs interface  (0) 2021.12.22