[Effective-Typescript] Item-15

JUNHO YEOM·2022년 11월 23일
0

Effective-TypeScript

목록 보기
1/1
post-thumbnail

Item 15 동적 데이터에 인덱스 시그니처 사용하기

인덱스 시그니처 사용하여 매핑 표현하기

type Rocket = {[property: string]: string};
const rocket: Rocket = {
  name: 'Falcon 9',
  variant: 'v1.0',
  thrust: '4,940 kN',
};  // OK

타입스크립트에서는 인덱스 시그니처를 이용하여 객체의 타입을 매핑할 수 있습니다.
각각의 키와 타입을 지정하지 않고 한번에 키와 밸류의 타입을 지정할 수 있습니다.
하지만 인덱스 시그니처는 포괄적인 타입선언이기 때문에 모든 키값을 허용하고,
타입스크립트의 언어서비스가 동작하지 않는 등의 특징을 가지고 있습니다.

인덱스 시그니처

{[property: string]: string};
키의 이름: 키의 위치만 표시하는 용도, 타입 체커에서는 사용하지 않습니다.
키의 타입: string이나 number 또는 symbol의 조합이어야 하지만, 보통은 string을 사용합니다.
값의 타입: 어떤 것이든 될 수 있습니다.

인덱스 시그니처의 단점

  • 잘못된 키를 포함해 모든 키를 허용한다.
  • 특정 키가 필요하지 않게 된다.
  • 키마다 다른 타입을 가질 수 없게 된다.
  • 타입스크립트의 언어 서비스가 동작하지 못하게 된다.

인덱스 시그니처 사용 시기

인덱스 시그니처는 동적 데이터를 표현할 때 사용합니다.
헤더 행과 열에 이름이 있지만, 열 이름이 무엇인지 알 수 없을 때
인덱스 시그니처를 사용하여 타입을 적용할 수 있습니다.

인덱스 시그니처의 광범위함

interface Row1 { [column: string]: number }  // 너무 광범위함
type Row3 =
    | { a: number; }
    | { a: number; b: number; }
    | { a: number; b: number; c: number;  }
    | { a: number; b: number; c: number; d: number }; // 가장 정확하지만, 간결하지 않음.
interface Row2 { a: number; b?: number; c?: number; d?: number }  // 최선

타입은 가능한 명확하게 지정하는 것이 좋기 때문에
만약 a, b, c, d와 같은 제한적인 키만 제공되지만,
a, b, c, d의 키값이 올 수도 있고 안올 수도 있는 데이터라고 하더라도
인덱스 시그니처를 사용하는 것보다 선택적 필드 또는 유니온 타입을 사용합니다.

인덱스 시그니처를 사용하게 된다면, 키가 string이고, 값이 number라면 어떤 값이든 허용하게 될 것입니다.



매핑된 타입 사용하기(타입의 특정키에 별도의 타입 넣어주기)

type Vec3D = {[k in 'x' | 'y' | 'z']: number};

type ABC = {[k in 'a' | 'b' | 'c']: k extends 'b' ? string : number};
// Type ABC = {
//   a: number;
//   b: string;
//   c: number;
// }
// k가 'b'이면 string타입을, 아닐때는 number타입으로

Vec3D타입과 비교해보면, b는 string 타입을 가지게 된 것을 알 수 있습니다.
솔직히 왜 이런 방법을 사용해서 b만 string으로 사용학게 조건을 거는 방식을 사용했는지는 모르겠습니다.
다만, 저렇게 특정 키의 타입을 지정해서 별도로 지정할 수 있다는 방법 정도만 기억해 두려고 합니다.


요약

  • 인덱스 시그니처는 런타임 때까지 객체의 속성을 알 수 없을 경우에만 사용합니다.
  • 인덱스 시그니처나 매핑된 타입보다 정확한 타입을 사용하는 것이 좋습니다.

인덱스 시그니처는 키값을 정확히 특정할 수 없는 제한된 조건에서 부분적이지만 타입을 지정할 수 있는 방법으로 사용할 수 있을 것 같습니다.

0개의 댓글