An index signature parameter type cannot be a literal type or a generic type
문제 발생
PortfolioItem.tsx 컴포넌트에서 사용할 디자인을 별도로 관리하던 중 발생한 문제입니다.
PortfolioItem은 포트폴리오 섹션(App, Web, Illustration...)에 따라 크기 비율이 다릅니다. 따라서 디자인 토큰처럼 별도 관리하려고 했습니다.
무슨 포트폴리오인지 구분하기 위해 props를 받게 되고, 그 props를 더 정확히 할 Section 타입을 정의했습니다.
type Section = 'Android/iOS' | 'Web' | 'Illustration' | 'Graphics' | 'Video';
그리고 스타일 객체를 위한 타입을 정의했습니다.
// src/types/style.ts
import { Section } from "./portfolio"
export type PortfolioItemSize = {
[key: Section]: { // 에러 발생
aspectRatio: string
}
}
그리고 다음과 같은 에러가 발생했습니다.
An index signature parameter type cannot be a literal type or a generic type
원인
key 타입은 string, number, symbol 혹은 리터럴 타입일 수 없다고 합니다.
해결 방법
해결 방법은 여러 가지가 있었습니다.
1. mapped type 사용하기
// enum일 경우
enum EmailStatus {
Read = 'READ',
Unread = 'UNREAD',
Draft = 'DRAFT',
}
// union일 경우
type EmailStatuses = 'Read' | 'Unread' | 'Draft';
// 👇️ 아래와 같이 사용(인터페이스 x)
type Status = {
[key in EmailStatus]: string;
};
인덱스 시그니처에 in 키워드를 사용하는 방법입니다.
단, 만약 mapped type을 인터페이스에서 타입 별칭 대신 사용한다면 에러가 발생한다고 합니다.
interface Status {
// ⛔️ Error
[key in EmailStatus]: string;
};
mapped type은 enum과 union 프로퍼티에 한하여 사용하기로 합시다.
2. Record utility type 사용하기
Record 유틸리티 타입은 키, 값의 type을 기반으로 구성됩니다.
// emum 사용할 경우
enum EmailStatus {
Read = 'READ',
Unread = 'UNREAD',
Draft = 'DRAFT',
}
type Status = Record<EmailStatus, string>
// union 사용할 경우
type EmailStatuses = 'Read' | 'Unread' | 'Draft';
// Record utility type
type StatusFromUnion = Record<EmailStatuses, string>
결과는 mapped type을 사용했을 때와 동일합니다.
참고 사이트
An index signature parameter type cannot be a literal type or a generic type | bobbyhadz
A step-by-step guide on how to solve the error An index signature parameter type cannot be a literal type or a generic type.
bobbyhadz.com