본 문서에서는 타입스크립트에서 다형성을 구현하는 방법 중 하나인 제네릭 타입에 대해서 다룬다.
최종수정일 : 2023.08.07
임의 타입의 배열을 매개변수로 받아 각 원소에 대해 특정 동작을 수행하는 함수에 대해 다음과 같이 확정타입(concrete type)으로 구현하는 과정을 살펴보고, 이로부터 일반화타입(generic type)의 필요성을 살핀다.
type Filter = { (userArray: number[], userFunction: (item: number) => boolean): number[]) (userArray: string[], userFunction: (item: string) => boolean): string[]) (userArray: object[], userFunction: (item: object) => boolean): object[]) } function Filter(userArray, userFunction) { let result = []; for(let i = 0; i < userArray.length; i++){ let item = userArray[i]; if(userFunction(item)) { result.push(item); } } return result; }
위 코드에서 object 타입의 객체는 object 타입이라는 것을 알려주는 것 이외에 객체에 대해서 아무것도 서술하지 않아 문제가 발생한다. 따라서 내부에 프로퍼티를 가진, 이름을 가진 object 타입을 매개변수로 건넨다고 해도, object 타입 내부에 접근할 수 없다.
따라서 임의 시점에 확정될 타입을 미지수 T라고 가정한다면, filter의 타입 선언을 다음과 같이 바꿔서 사용할 수 있다.
type Filter = { <T>(userArray: T[], userFunction:(item: T) => boolean): T[]
위에서 타입 T는 언젠가 <T>가 확정되어 <SpecificType>이 되었을 때 이어지는 구문에서 T를 모두 SpecificType으로 바꾸겠다는 의미이다.
//Case 1 type Filter = { <T>(array: T[], f: (item: T) => boolean): T[] } let filter: Filter = { //... //Case 2 type Filter<T> = { (array: T[], f: (item: T) => boolean): T[] } let filter: Filter<number> = { //... //Case 3 type Filter = <T>(array: T[], f: (item: T) => boolean) => T[] let filter: Filter = { //... //Case 4 type Filter<T> = (array: T[], f: (item: T) => boolean) => T[] let filter: Filter<number> = { //... //Case 5 function filter<T>(array: T[], f: (item: T) => boolean): T[] { //... }
Case 1
제네릭 타입 T는 Filter 타입 내의 특정 시그너처 중 하나로 할당된 것으로서, filter 함수가 호출 될 때, 해당 경우에 한해서만 확정타입으로 결정된다.
Case 2
제네릭 타입 T는 Filter 타입의 구성요소이므로, Filter 타입을 사용할 때 확정타입을 함께 명시하여야 한다.
Case 3
Case 1과 같은 효과를 지니는 단축 호출 시그너쳐
Case 4
Case 2와 같은 효과를 지니는 단축 호출 시그너쳐
Case 5
제네릭 타입 T는 매개변수와 반환값의 타입을 결정하는 한정된 범위를 가지며, 함수가 호출될 때 해당 호출에 대해서만 확정타입으로 결정된다.
많은 것을 배웠습니다, 감사합니다.