[TypeScript] 제네릭을 제한하려면 어떻게 해야 할까?

프론트 깎는 개발자·2023년 2월 19일
0

Typescript 를 써서 함수를 작성하려고 보면 제네릭 (Generic) 을 쓸 일이 종종 있다. 함수에는 인자를 넣어 전달할 수 있듯이, 일종의 '타입 인자' 같은 것인데, 보통은 T 와 같은 컨벤션으로 많이들 사용한다.

그런데 오늘 개발을 하다가 난관에 봉착했는데 바로 다음과 같은 상황이었다.

다음의 함수를 보자

export function selectDataMaker<T>(lookupTable: Record<T, string>) {
  return Object.entries(lookupTable).map(([value, label]) => ({ value, label }));
}

우선 Record 가 나오는데, 이는 특정 타입에 대한 어떤 lookup table 과 비슷한 것을 만들고자 할 때 유용하게 쓰인다. 자세한 내용은 이전 포스팅 여기 참고!

즉, 여기서 입력값인 lookupTable 은 어떤 T 라는 타입이 가질 수 있는 항목들을 key 로 갖고, 그 각각에 해당하는 value 로 string 형식이 오는 것이다.

예를 들어,

export type UserType = "admin" | "seller" | "customer"

export const USER_TYPE_LOOKUP_TABLE: Record<UserType, string> = {
	"admin" : "관리자", 
  	"seller" : "판매자", 
  	"customer" : "고객",
}

이런 식이다.

하지만 저런 상태의 함수로는 아래와 같은 error 가 뜬다.

즉, T 의 타입이 Record 의 첫 제네릭 인자로 오지 못하는 것이 올 수도 있다는 것이다. 왜냐하면 Record 의 첫 인자로는 string, number, symbol 밖에 오지 못하기 때문이다.

즉, 우리는 제네릭 <T> 에 이러한 제약을 걸어줘야 하는데, 바로 이 때 쓰는 것이 extends 이다.

아래와 같이 고쳐보자.

export function selectDataMaker<T extends string | number | symbol>(
  lookupTable: Record<T, string>
) {
  return Object.entries(lookupTable).map(([value, label]) => ({ value, label }));
}

여기서 이제 <T>string, number, symbol 로 제한된다.

그리하여 오류가 없어졌다. extends 를 이렇게 타입을 제한할 때도 활용할 수 있다!

참고자료


https://stackoverflow.com/questions/48539710/restricting-generic-types-to-one-of-several-classes-in-typescript

profile
Comfort Zone 에서 벗어나자!

0개의 댓글