Programming/TypeScript

string key로 객체에 접근할 때 타입(Index signatures type)

soyeori 2023. 5. 24. 14:38

프로젝트를 리팩토링 하면서 타입스크립트로 객체의 키를 사용하여 객체에 접근할 때 에러가 난 다는 사실을 발견했다. 

물론 이 에러는 자바스크립트에서 나타나는 에러가 아니다. 해당 코드로 자바스크립트에서는 객체의 프로퍼티에 접근하는 데에 아무런 문제가 없다. 오류를 해결하기 위해 타입스크립트에서 새롭게 알게 된 부분이 있어서 정리해 보려 한다.

문제 상황

접근하려고 하는 객체에는 interface를 사용하여 각 프로퍼티에 들어올 값의 타입을 지정해 준 상태이고, for...in 문을 사용하여 각각의 프로퍼티에 접근을 시도하려는 중이었을 때, inputs [key]에 다음과 같은 에러문구가 발생했다.

  // 에러가 발생한 코드
   for (let key in inputs) {
      if (inputs[key] === "") {
        message.warning({ content: "필수값을 입력해주세요." });
        break;
      }
    }

  • type 'string'은 IinputsType을 인덱스 하는 데 사용할 수 없기 때문에 암시적으로 'any'타입을 가진다.
  • 'string' 타입을 가진 어떤 인덱스 시그니처도 IinputsType에서 발견되지 않았다.
  • 참고로 IinputsType이란 인터페이스를 사용해서 지정해 준 inputs 객체의 타입이다.

여기서 드는 의문은,

  • 인덱스 하려는 객체에 이미 타입을 지정해 놓은 상태인데 무슨 타입이 발견되지 않았다는 것인가
  • stirng타입은 왜 객체 타입을 인덱스 하는 데 사용할 수 없는 것인가 

Index Signatures

구글링을 해보니 인덱스를 위한 타입을 객체에 지정을 해 줘야 한다는 것이었다. 타입스크립트 공식문서에서 Index signature 키워드로 검색해 보니 Object Types 페이지에 다음과 같이 설명이 되어있다.

 

  • 접근하려는 값의 타입은 알고 있지만, 접근하려는 프로퍼티의 이름을 미리 알지 못하는 경우, Index signature을 사용하여 가능한 값의 타입을 묘사할 수 있다.
  • Index signature을 설정한 인터페이스에서 숫자로 객체에 접근할 때 반환받는 값(secondItem)이 string 타입임을 알 수 있다.

 

공식문서를 읽고 난 후 아까 전 드는 의문이 이렇게 해석될 수 있다.

  • 인덱스 하려는 객체에 이미 타입을 지정해 놓은 상태인데 무슨 타입이 발견되지 않았다는 것인가
    ㄴ 객체에 타입과는 별개로 객체에 접근하는 상황에 대한 타입을 Index signature을 사용하여 지정해야 한다.
  • stirng타입은 왜 객체 타입을 인덱스 하는 데 사용할 수 없는 것인가 
    ㄴ string타입이 인덱스를 하기 위해 사용할 수 없다는 의미가 아니고, 문자열로 인덱스 하려는 인터페이스에 실제로 정의된 프로퍼티가 있는지 확인이 어려워서 인덱스 하는 데 사용할 수 없다는 의미로 해석할 수 있다. 첫 번째 의문과 같은 맥락으로 Index signature로 key와 반환받을 value의 타입을 지정해 주지 않았으니 TypeScript에서 해당 인터페이스에 접근할 때 프로퍼티의 존재여부를 확인할 수 없고, 그러므로 오류가 발생한다.

그렇다면 객체에 접근할 때  반복문으로 접근하지 않고 구체적인 키 값을 넣어서 접근하면 객체 인터페이스에 접근이 가능하다는 뜻일까?라는 생각이 들었다. 우선, 접근을 시도했던 객체의 타입으로 다음과 같이 프로퍼티를 가진 타입이 선언되어 있다. 

// IinputsType 타입
export interface IinputsType {
  writer: string;
  password: string;
  title: string;
  contents: string;
  youtubeUrl: string;
}

맨 처음 for...in문으로 접근을 시도했던 방법으로 이번엔 key부분에 구체적인 속성을 명시해 보니 에러가 사라졌다. string key인 'contents'부분에 마우스오버하니 반환값으로 string이 정확하게 표시됨을 알 수 있었다. 그렇다면 단순히 key가 stirng 타입이어서 접근이 되지 않았던 것이 아니고 반환받을 타입이 무엇인지 모르는 상태에서 구체적인 접근하지 않았기 때문임이 확실해졌다.

 

마무리

이제 최종 에러를 해결하기 위해 인터페이스에 docs에 나와있는 대로 Index signature를 인터페이스에 추가해 주었고, 더 이상 에러가 나지 않았다. 참고로 [key: string] 부분에서 key는 꼭 key로 작성해야 하는 정해진 키워드가 아니고 임의로 작성해 주면 된다.

// index signature type 지정
export interface IinputsType {
  [key: string]: string; 
  writer: string;
  password: string;
  title: string;
  contents: string;
  youtubeUrl: string;
}

참고

타입스크립트 Docs