My Boundary As Much As I Experienced

인덱스 시그니처란? 본문

FrontEnd/TypeScript

인덱스 시그니처란?

Bumang 2024. 5. 4. 17:54

타입스크립트에서 인덱스의 타입을 지정할 때 사용하는 두 개념이다.

두 개념이 밀접한 관련이 있는 개념이지만 엄밀히 말하면 다르긴 하다.

하지만 자주 인덱스 시그니처를 인덱스 타입이라고 부르는 사람도 발생하는 등 조금은 용어 사용이 엄격하지 못한 채로 사용된다.

 

일단 인덱스 시그니처 먼저 이번 시간에 다뤄보겠다.

  • 인덱스 시그니처는 인덱스 타입 정의의 일부로서, 객체가 어떤 형태의 키와 값을 가질 수 있는지를 정의한다.

쉽게 말하자면, 인덱스 시그니처는 '객체 형태의 타입'에서 '속성의 키'를 정의할 때 사용되는 문법이다.

 

인덱스 시그니처 (Index Signature)

인덱스 시그니처는 특정 객체가 다양한 키를 가질 수 있고, 각 키의 값이 어떤 타입을 가져야 하는지 명시한다.

기본적으로 인덱스 시그니처는 타입을 좀 더 동적으로 처리할 수 있게 해준다. 예시를 보자.

// 인덱스 시그니처 예시
interface StringDictionary {
  [key: string]: string; // 인덱스 시그니처
}

const FruitDict = {
  A: "Apple",
  B: "Banana",
  C: "Coconut"
}


// 일부만 인덱스 시그니처로 만들 수 있다.
interface MixedDictionary {
    [key: string]: number | string; // 인덱스 시그니처
    fixedProperty: boolean; // 명시적으로 정의된 속성
}

let obj: MixedDictionary = {
    fixedProperty: true, // 명시적 속성
    dynamicProperty1: 42, // 인덱스 시그니처에 따른 속성
    dynamicProperty2: "value" // 인덱스 시그니처에 따른 속성
};

 

'[key: keyValue] : value' 형태로 사용한다. 키값에 대괄호를 넣어 동적으로 여러 값을 허용하는게 ES6의 ComputedPropertyName과 유사한 면이 있다. (관련 내용: https://bumang.tistory.com/160)

 

 

인덱스 시그니처가 실제 유용한 경우

사실 이 인덱스 시그니처를 알게 되고 사용하게 된 계기는 아래와 같다.

interface Objs {
  id: string;
}

const idObject: Objs = {
  id: "string"
}

const constant = {
  idKey: "id" 
}

// 결과는?
console.log(idObject[constant["idKey"]])

 

위는 constant용 객체에 상수값을 적어놓고 이를 활용하는 경우이다.

constant["idKey"]가 "id"를 반환하고,

idObject["id"]가 "string"을 반환하니

"string"이 나올것이라 예상했나?

 

결과적으론 '"id"에 string을 지정할 수 없다는 에러'가 뜬다.. 왜냐하면

interface Objs에 id라는 매우 구체적인 키값을 사용했기 때문이고,

constant["idKey"]가 언제나 "id"라는 보장이 없기 때문이다.

(이렇게 구체적으로 타입지정을 해둘수록, 개발 시 겪게 되는 에러는 많아진다ㅠ)

 

이럴 경우 어떻게 해결하면 되나? 해결 방법은 방금 배운 인덱스 시그니처를 사용하거나, 타입 단언을 사용하면 된다.

// 선언 시 인덱스 시그니처 사용
// 일단 string은 모두 허용하기 때문에 조금 더 헐거워진 타입체크를 하게된다.
interface Objs {
  id: string;
  [key: string]: string;  // 인덱스 시그니처 추가
}


// 타입 단언을 사용할 시
console.log(idObject[constant["idKey"] as keyof Objs]);