yehey's 공부 노트 \n ο(=•ω<=)ρ⌒☆

[Typescript] 'string' 형식의 식을 인덱스 형식에 사용할 수 없으므로 요소에 암시적으로 'any' 형식이 있습니다. 본문

적어보자 에러 일지

[Typescript] 'string' 형식의 식을 인덱스 형식에 사용할 수 없으므로 요소에 암시적으로 'any' 형식이 있습니다.

yehey 2023. 12. 27. 15:23

Background

Typescript 기반으로 Next, styled-components 를 사용해서 개발 중 constant 값에 변수로 접근해야하는 경우가 있었다. 그런데 타입스크립트에서 object를 변수로 접근하려니 typescript warning? error 가 발생했다.

Issue / Error

현재 color 를 정해놓고 color.ts 에 두고 필요한 곳에서 불러서 사용하고 있다.

// color.ts
export const WHITE = '#FFFFFF';
export const BLACK = '#000000';
export const GREY = {
  100: '#B3B3B3',
  200: '#4E4E4E',
  300: '#D9D9D9',
};
export const MAJOR_GREEN = {
  100: '#8ACCB8',
  200: '#68AF9A',
  300: '#E8F5F1',
};
export const LEDGER_BACKGROUND = {
  2: '#F3F1CC',
  3: MAJOR_GREEN[300],
  4: '#DDD9E6',
  5: '#F5E1E1',
};

export const LEDGER_HASHTAG_COLOR = {
  2: '#D6CF14',
  3: MAJOR_GREEN[200],
  4: '#A496C3',
  5: '#CA9F9F',
};

const color = {
  WHITE,
  BLACK,
  GREY,
  MAJOR_GREEN,
  LEDGER_BACKGROUND,
  LEDGER_HASHTAG_COLOR,
};

export default color;
const Wrapper = styled.div<{ categoryID: string }>`
  padding: 1.2rem 1.5rem;
  background-color: ${(props) => theme.color.LEDGER_BACKGROUND[props.categoryID]};
  width: 100%;
  /* height: 4.2rem; */
  display: flex;
  flex-direction: column;
  border-radius: 10px;
  margin-bottom: 0.5rem;
`;

그리고 위와 같이 Wrapper 컴포넌트를 categoryID를 기반으로 색이 달라지도록 구성하려고 했는데, 여기서 에러가 발생한다. (엄밀히 따지면 타입에러라 실행에는 문제가 없지만 빨간 줄이 싫다. 그리고 타입에러도 타입스크립트를 쓴다면 에러...)

[{
    "resource": "/Users/yehey/Documents/projects/household-ledger-client/src/components/ledgers/LedgerItem.tsx",
    "owner": "typescript",
    "code": "7053",
    "severity": 8,
    "message": "'string' 형식의 식을 '{ 2: string; 3: string; 4: string; 5: string; }' 인덱스 형식에 사용할 수 없으므로 요소에 암시적으로 'any' 형식이 있습니다.\n  '{ 2: string; 3: string; 4: string; 5: string; }' 형식에서 'string' 형식의 매개 변수가 포함된 인덱스 시그니처를 찾을 수 없습니다.",
    "source": "ts",
    "startLineNumber": 51,
    "startColumn": 34,
    "endLineNumber": 51,
    "endColumn": 81
}]

간단하게 말하면.. LEDGER_BACKGROUND의 타입을 봤을 때, '{ 2: string; 3: string; 4: string; 5: string; }' 인데? 너가 준 props.categoryID는 string 인데 여기 key(인덱스)에 string 타입은 없는데?? 라는 것이다.
TypeScript는 기본적으로 객체를 읽을 때 string타입의 key사용을 허용하지 않기 때문에 발생한 에러다.

My Solution

없으면 만들어주면 된다. 필요한 ColorType 을 만들어주었다.

After

type ColorType = {
  [index: string]: string;
};

export const WHITE = '#FFFFFF';
export const BLACK = '#000000';
export const GREY: ColorType = {
  100: '#B3B3B3',
  200: '#4E4E4E',
  300: '#D9D9D9',
};
export const MAJOR_GREEN: ColorType = {
  100: '#8ACCB8',
  200: '#68AF9A',
  300: '#E8F5F1',
};
export const LEDGER_BACKGROUND: ColorType = {
  2: '#F3F1CC',
  3: MAJOR_GREEN[300],
  4: '#DDD9E6',
  5: '#F5E1E1',
};

export const LEDGER_HASHTAG_COLOR: ColorType = {
  2: '#D6CF14',
  3: MAJOR_GREEN[200],
  4: '#A496C3',
  5: '#CA9F9F',
};

const color = {
  WHITE,
  BLACK,
  GREY,
  MAJOR_GREEN,
  LEDGER_BACKGROUND,
  LEDGER_HASHTAG_COLOR,
};

export default color;

Error Review

타입스크립트를 사용하며 객체 key를 변수로 사용한 적이 없었나.. 아니면 그동안은 무시하고 넘겨왔던걸까...? 그래도 알아간다.. 타입스크립트 쓰면서 항상 하는 생각은 귀찮을 때도 있지만 없으면 안 될 것 같다. javascript 였다면 에러조차 나지 않았을 상황이지만, 추후에 알 수 없는 곳에서 시작된 에러를 미리 생각하고 진행할 수 있다는 점이 타입스크립트의 장점이라고 한번 더 느낀다.

위와 같은 해결방법에서 문제점도 분명 있다. 값이 보장되어있지 않은 상황에서 정해지지 않은 key 가 입력으로 들어오면 undefined 를 뱉는다. 그렇기에 key를 변수로 사용하면서 항상 조심해야한다. 추가로 key를 사용할 때 해당 key가 유효한지 판단하는 로직을 추가하는 방법을 추가하고자 한다.

Comments