TypeScript-제네릭 타입(Generic-Type)
제네릭 타입 (Generic Type)
-
제네릭 타입은 C#, Java 등의 언어에서 컴포넌트를 재사용성 높게 하기위해서 사용하는 방식이다. 제네릭 타입을 지원하는 언어를 사용했었다면 타입스크립트에서도 쉽게 이해하고 사용하는데 무리가 없을것이다. 여러 장소에 타입 수준의 제한을 적용할 때 사용하는 플레이스홀더 타입(placeholder type) 또는 다형성 타입 매개변수(polymorphic type parameter) 라고 부른다. 그리고 보통 사람들이 제네릭 타입 또는 제네릭 이라고 많이 불러서 사용한다.
-
제네릭을 완전 처음 접해보는 사람이 있을수도 있기때문에 간단하게 제네릭의 사용법을 설명하자면 꺽쇠괄호(<>) 로 제네릭 타입 매개변수임을 선언하고 꺽쇠기호를 추가하는 위치에 따라서 제네릭의 범위가 결정되며 타입스크립트는 지정된 영역에 속하는 모든 제네릭 타입 매개변수 인스턴스가 한 개의 구체 타입으로 한정되도록 보장해준다.
type Filter = { <T>(array: T[], f: (item: T) => boolean): T[], }
-
위 코드는 filter함수에 제네릭 타입 매개변수 T를 적용한 코드이다. 코드를 그대로 해석해보면 filter 함수는 T라는 제네릭 타입 매개변수를 사용하는데 이 타입이 지금은 무엇인지 알 수 없으니 어디선가 filter를 호출할 때마다 타입스크립트가 타입을 알아서 추론해줘. 라는 방식이다. 타입스크립트는 전달된 배열의 타입을 보고 T의 타입을 추론한다. filter를 호출한 시점에 타입스크립트가 T의 타입을 추론하면 filter에 정의된 모든 T를 추론한 타입으로 대체한다. T는 자리를 맡아둔다는 의미의 위에서 말한 플레이스홀더 타입이며 타입 검사기가 문맥을 보고 이 플레이스홀더 타입을 실제 타입으로 채워준다. 위와 같이 T는 filter의 타입을 매개변수화한다. 그래서 이 T를 제네릭 타입 매개변수라고 부른다.
-
함수의 매개변수가 함수를 호출할 때 건네진 인수로 매번 다시 한정되듯, T도 filter를 호출할 때마다 새로운 타입으로 한정된다.
type Filter = { <T>(array: T[], f: (item: T) => boolean): T[], } // T는 number로 한정됨 filter([1, 2, 3], (_) => _ > 2) // T는 string으로 한정됨 filter(['a', 'b'], (_) => _ !== 'b') // T는 {name: string}으로 한정됨 let names = [{ name: 'lee' }, { name: 'leeseung' }, { name: 'leeseunggyu' }] filter(names, (_) => _.name.startsWith('lee'))
-
위 예제중 첫 번째 filter함수를 간단하게 순서대로 살펴보면 filter의 타입 시그니처를 통해서 array가 아닌 타입이 T인 요소들로 이루어진 배열이 만들어진다. 그리고 전달된 인수 array[1,2,3]을 통해 T는 number라는 사실을 알게 된다. 이제 모든 T를 number 타입으로 대치하게되고 그에 따라서 매개변수 f: (item: T) => boolean은 f: (item: number) => boolean이 되고 반환 타입 T[]는 number[]가 된다. 그 후 모든 타입이 할당 조건을 만족하는지 전달받은 함수 f를 새로 추론한 시그니처에 할당할 수 있는지 확인한다.
-
제네릭은 함수의 기능을 (구체 타입을 사용할때 보다) 더 일반화하여 설명할 수 있는 좋은 도구이다. 제네릭을 제한 기능으로 생각할 수 있다. 함수 매개변수를 n: number 같이 정해 매개변수 n의 값으로는 number 타입만 오도록 제한하듯 제네릭도 T를 T로 한정하는 타입이 무엇이든 모든 T를 같은 타입으로 제한한다.
-
타입 별칭, 클래스, 인터페이스에서도 제네릭 타입을 사용할 수 있다. 가능하면 제네릭을 사용하는건 좋고. 제네릭은 코드를 일반화하고, 재사용성을 높이고, 간결하게 유지하는 데 도움을 준다.
-
마지막으로 T는 단지 타입 이름이다. T 대신 아무 이름을 사용할 수 있다. 일반적으로 타입 이름은 대문자 T를 시작으로 U,V,W 순으로 필요한 만큼 사용한다. 또는 T대신 A부터 시작하는 것을 선호하는 사람들도 있고 함수형 언어를 사용하는 사람들은 A,B,C를 선호한다고하고 객체지향 개발자들은 T를 선호한다고 한다. 각자 본인에 맞게 사용하면 될 것 같다. 타입스크립트는 두 프로그래밍 스타일을 모두 지원하지만 T 방식을 사용해서 나 또한 T를 사용하고 있다.