본문 바로가기

IT

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

타입스크립트의 인덱스 시그니처란? 동적인 Property 를 다루기에 유용하게 활용 될수 있다. 아래는 그 예제이다.

// 인덱스 시그니처의 예
type Pet = {
    [property : string] : string; // <- 인덱스 시그니처 (property라는 키 이름은 더미이다.)
};
const kitty: Pet = {
    name : 'Nabi',
    home : 'my house',
    owner : 'Peter'
}

하지만 위 예제와 같은 방법으로 인덱스 시그니처를 활용하면 몇 가지 단점이 있습니다.

a. 의도하지 않은 모든 키를 허용합니다.

b. 특정 키가 필요하지 않습니다. 따라서 위 예제를 기준으로 Pet type 변수에 '{}' 와같은 빈 object를 assign 하더라도 오류가 아닙니다.

c. key 마다 다른 타입을 가질수 없습니다.

 

그래서, 위 몇가지 단점을 극복하면서 인덱스 시그니처를 사용할만한 상황은 무엇일까? 아래 예제를 참고하자.

// 아래 예제와 같이 몇개의 key가 할당 될 수 있을지 예상이 되지 않는 상황에서는
// 인덱스 시그니처를 활용하여 타입을 활용 할수 있다.
function parseExcel(input: string): {[columnName: string]: string}[] {
    const lines = input.split('\n');
    const [header, ...rows] = lines;
    const headerColumns = header.split(',');
    return rows.map(rowStr =>{
        const row: {[columnName: string]: string} = {};
        rowStr.split(',').forEach((cell, i) =>{
            row[headerColumns[i]] = cell;
        });
        return row;
    });
}

 

그리고, 인덱스 시그니처를 사용했을 때 타입의 범위가 너무 광범위해 지기 때문에, 때에 따라서는 Record 제네릭 타입과 조건부 타입을 활용하는 상황이 있을 수 있다.

type Vec3D = Record<'x' | 'y' | 'z', number>;
// type Vec3D = {
//     x: number;
//     y: number;
//     z: number;
// }

type ABC = {
    [k in 'a' | 'b' | 'c']: k extends 'b' ? string : number;
}
// type ABC = {
//     a: number;
//     b: string;
//     c: number;
// }

요약

* 런타인 상황에서도 object의 속성(property)을 알기 어려운 상황에서는 인덱스 시그니처를 활용한 타입 명세가 유용할 수 있다.