Studying/JavaScript

An index signature parameter type cannot be a literal type or a generic type

Kim Da Ham 2023. 8. 20. 21:48

문제 발생

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