[타입시스템 15] 인덱스 시그니처

2022. 7. 19. 23:38책/이펙티브 타입스크립트

1. 인덱스 시그니처

  • { [ key :T ] :U } 형식으로 객체가 여러 키를 가질 수 있게 선언하는 타입을 말한다
  • 이때 key의 타입은 string, number, symbol의 조합만 가능하다(보통 string 씀)
  • 동적인 데이터의 타입을 정하기엔 좋으나 타입으로서는 부정확하다
  • 따라서 런타임 때까지 객체의 속성을 알 수 없는 경우에만 인덱스 시그니처를 사용하자

2. 인덱스 시그니처 대안
사실 런타임 때까지 객체의 프로퍼티를 죽어도 모르겠다면 딱히 대안이랄 게 없다. 다만 a, b, c, d, e,... 정도 선에서 걸러낼 수 있다면 정확한 타입 선언을 위해 최대한 머리를 굴려봐야 한다.

2.1 선택적 필드(or 유니온 타입)

// 이렇게 너무 광범위하게 지정하는것 보단
// a,b,c,d,e, ... 선에서 정리되는 수준이라면
// 아래처럼 선언하는게 차라리 낫다
interface Row { [column :string] :number };
interface Row { a :number; b? :number; c? :number; d? :number; }


2.2 Record <K, T> 사용하기
<K> 타입의 프로퍼티 키를 가지며, 그 값이 <T> 타입인 객체 타입을 반환한다.

// 결과적으론 1번 예시와 같지만 좀더 간단하게 선언하는 방법이다
type RowKey = 'x' | 'y' | 'z';
type Row = Record<RowKey, number>;


2.3 매핑된 타입 사용하기
결국 2.1, 2.2 예시와 같은 내용이지만 키마다 별도의 타입을 지정할 수 있어 쓰기에 따라선 활용도가 더 높을 수 있다.

type Row = {
  [key in 'a' | 'b' | 'c'] : key extends 'b' ? string : number;
}


3. 결론
다시 한번 말하지만 런타임 때까지 타입을 죽어도 알 수 없다면 인덱스 시그니처를 쓰는 게 맞다. 그러나 얼추 추론이 가능하다면 최대한 명시적으로 타입을 선언해야 한다.