웹사이트 검색

타입스크립트 - 'string' 타입의 표현식은 해당 타입의 인덱스로 사용할 수 없습니다


// common.js

const boxNames = ['one', 'two'];

module.exports {
  boxNames,
}
const common = require("./common.js");
const boxNames = common.boxNames;
const messages = {
  'one': {
      id: 'some id',
      text: 'some text',
  },
  'two': {
    id: 'some id',
    text: 'some text',
  },
};
const disabled = boxNames.map((key: string) => messages[key]);

위 코드는 messages[key] 문장에서 TypeScript 오류를 발생시킵니다:

TS7053: 문자열 타입의 식을 '{ one: { id: string; text: string; }; two: { id: string; text: string; }; }' 타입의 인덱스로 사용할 수 없기 때문에 요소가 암묵적으로 'any' 타입을 가집니다. '{ one: { id: string; text: string; }; two: { id: string; text: string; }; }' 타입에서 문자열 타입 매개변수를 가진 인덱스 서명을 찾을 수 없습니다.

저는 key를 문자열로 선언하고 messages의 키들도 문자열인데, 문제는 무엇인가요?

(여기서 주목할 점은 messages가 react-intl 라이브러리의 defineMessages 메서드를 사용하여 생성된다는 것입니다.)

(저는 StackOverflow에서 Object.keys를 언급하는 이와 유사한 몇 가지 답변을 본 적이 있지만, 이것이 제 TypeScript 오류와 어떻게 관련이 있는지는 잘 모르겠습니다.)

답변 #1

객체 messages의 키는 string 타입이 아니라 "one" | "two" 타입입니다. 다시 말해, 이들은 단순한 string보다 더 좁은 타입인 문자열 리터럴이며, 더 넓은 string 타입으로 인덱싱할 수 없습니다.

예제를 컴파일되도록 만드는 간단한 방법은 키 배열을 튜플로 바꾸는 것입니다:

const boxNames = ['one', 'two'] as const;

이것은 실질적으로 타입을 string[]에서 ["one", "two"]로 변경하며, 이제 이들을 맵으로 순회할 때 객체를 인덱싱할 수 있는 올바른 타입이 됩니다. 참고로, key의 타입을 명시적으로 설정할 필요는 없는데, 사용법으로부터 타입을 추론할 수 있기 때문입니다.

const disabled = boxNames.map((key) => messages[key]); // this is now fine

이것을 입력하는 또 다른 방법은 messages의 키를 배열에 할당하는 것입니다:

const messages = {
  'one': {
      id: 'some id',
      text: 'some text',
  },
  'two': {
    id: 'some id',
    text: 'some text',
  },
};

const boxNames: (keyof typeof messages)[] = ['one', 'two'];

const disabled = boxNames.map((key) => messages[key]);

이는 튜플을 사용하는 것보다 더 동적이며, messages의 키로 존재하는 것보다 더 많은 문자열을 boxNames에 포함할 수 없기 때문에 타입 안전성을 유지합니다. 지금 바로 테스트할 환경이 갖춰져 있지는 않지만, 말씀하신 require 시나리오에서도 여전히 작동할 것이라고 상상합니다.

여기서 가장 중요한 요점은 boxNames가 더 구체적인 타입을 가져야 하거나, messages가 덜 구체적인 타입을 가져야 한다는 것입니다. 저는 이 키들이 정확히 일치해야 한다고 가정하고 있지만, 상황에 따라 messages에 string 인덱스 타입을 할당하는 것이 실제로 더 나을 수도 있습니다. 여기에는 어느 쪽이 맞는지 판단할 충분한 맥락이 없는 것 같습니다. 이는 코드에서 배열과 객체가 런타임에 실제로 일치하는지 알 수 없는 가능성을 처리해야 함을 의미합니다.

답변 #2

TypeScript는 boxNames의 요소들이 messages의 키라는 것을 알지 못합니다.

string과 keyof 사이에는 명확한 구분이 있습니다.

문자열이 객체의 키임을 TS에 알려주는 몇 가지 방법이 있습니다.

제가 직접 테스트하지는 않았지만, 여러분은 이렇게 할 수 있을지도 모릅니다:

boxNames.map((key: keyof typeof messages) => messages[key])

당신은 keyof 키워드를 사용하는 방법을 찾아보고 싶어하며, 엄격 모드에서 객체를 인덱싱하는 것이 필요합니다.

관련기사