Table of contents

6.2.0. Introduction

소프트웨어 엔지니어링에서 가장 주요한 부분 중 하나는 컴포넌트를 만드는 일이다. 이 컴포넌트는 잘 정의되고 일관적인 API를 가져야 함은 물론이고, 재사용이 가능해야 한다. 현재 시점의 데이터와 미래 시점의 데이터를 모두 다룰 수 있는 컴포넌트는 대규모의 소프트웨어 시스템을 구성함에 있어 최상의 유연성을 제공할 수 있을 것이다.

C#이나 Java와 같은 언어에서, 재사용 가능한 컴포넌트를 만들기 위한 주요 툴 중 하나는 *제네릭(generic)*이다. 이 제네릭은 단일 요소보다는 여러 타입에 동작할 수 있는 컴포넌트를 생성하는 데 도움을 준다. 이는 사용자로 하여금 생성된 컴포넌트들을 자신들만의 타입에 적용하여 사용할 수 있도록 해준다.

6.2.1. Hello World of Generics

identity라는 함수로 제네릭을 시작해보자. identity함수는 어떤 값이 들어오든 간에, 그 값을 바로 반환해주는 함수다.

제네릭이 없다면, 다음과 같이 작성하여 입력과 반환을 특정 타입에만 한정하게 될 것이다.

function identity(arg: number): number {
	return arg;
}

또는, any 타입을 사용하여 다음과 같이 작성할 수도 있을 것이다.

function identity(arg: any): any {
	return arg;
}

any를 쓰는 것은 함수의 arg 가 어떤 타입이든 받을 수 있다는 점에서 제네릭이지만, 실제로 함수가 어떤 타입을 반환할지에 대한 정보는 잃게 된다. 만약 number 타입을 넘긴다고 해도 any 타입이 반환된다는 정보만 얻을 뿐이다.

대신, 우리는 무엇이 반환되는지 표시하기 위해 인수의 타입을 캡쳐할 방법이 필요하다. 여기서는 값이 아닌 타입에 적용되는 *타입 변수(type variable)*을 사용할 것이다.

-generic-basic.ts-

function identity<Type>(arg: Type): Type {
	return arg;
}

identity 함수에 Type 이라는 타입 변수를 추가했다. Type은 유저가 준 인수의 타입을 캡쳐하고(예 - number), 이 정보를 나중에 사용할 수 있게 한다. 여기에서는 Type을 반환 타입으로 다시 사용한다. 인수와 반환 타입이 같은 타입을 사용하고 있는 것을 확인할 수 있다. 이를 통해 타입 정보를 함수의 한쪽에서 다른 한쪽으로 운반할 수 있게끔 한다.

이 버전의 identity 함수는 타입을 불문하고 동작하므로 제네릭이라 할 수 있다. any를 쓰는 것과는 다르게, 인수와 반환 타입에 number를 사용한 경우(identity<number>), 이 챕터 가장 위 예제의 identity 함수처럼, 인수의 타입과 반환 타입이 number가 되는 정확성을 가진다.(즉, 어떤 정보도 잃지 않는다)