DEV Community

Cover image for Typescript에서 객체의 프로퍼티를 programatically 참조하는 방법
Herbert Lim
Herbert Lim

Posted on • Edited on

Typescript에서 객체의 프로퍼티를 programatically 참조하는 방법

이슈

Javascript에서는 객체의 프로퍼티를 programatically 접근하기 위하여 대괄호 표기법 object['propertyName']을 흔히 사용한다. 다음 예제는 sample 객체의 각 프로퍼티를 sample['taMin' + i]으로 참조하는 예제이다.

const sample = {
  taMin0: 355,
  taMin1: 455,
  taMin2: 555,
  taMin3: 655,
}

for (let i=0; i<4; i++) {
  console.log( sample['taMin' + i] )
}
Enter fullscreen mode Exit fullscreen mode

내가 짠 Javascript 프로그램에서는 이런 예가 정말 많다. Typescript 에서는 아래와 같이 IAbc 라는 인터페이스 타입을 정의하고 sample 객체를 초기화하면 될 줄 알았다.

interface IAbc {
  taMin0: number;
  taMin1: number;
  taMin2: number;
  taMin3: number;
}

const sample: IAbc = {
  taMin0: 355,
  taMin1: 455,
  taMin2: 555,
  taMin3: 655,
}

for (let i=0; i<4; i++) {
  console.log( sample['taMin' + i.toString()] )
}
Enter fullscreen mode Exit fullscreen mode

그러나 tsc를 실행해보면 for 문 안의 sample['taMin' + i.toString()] 에서 다음과 같은 오류가 발생한다.

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'IAbc'. No index signature with a parameter of type 'string' was found on type 'IAbc'.

해석하자면 sample 객체의 인덱스로 준 'taMin' + i.toString()string 타입인데, 이 타입은 IAbc의 인덱스(키) 타입과 다르다는 것이다.

 

type assertion

구글링을 통해 힌트를 얻은 곳은 Stackoverflow의 다음 글에 있는 답변이다.

161

When using Object.keys(obj), the return value is a string[], whereas I want a (keyof obj)[].

const v = {
    a: 1,
    b: 2
}

Object.keys(v).reduce((accumulator, current) => {
    accumulator.push(v[current]);
    return accumulator;
}, []);

I have the error:

Element implicitly has an 'any' type because type '{ a…

 

요지는 type assertion을 사용해야 한다는 것.


위 Stackoverflow 의 답변대로 keyof typeof 를 이용하여 아래와 같이 해결할 수 있다. 좌측의 상수 key 의 타입도 지정하고 오른쪽의 값도 동일한 타입으로 지정한다.

for (let i=0; i<4; i++) {
  const key: keyof typeof sample = 
    ('taMin' + i.toString()) as keyof typeof sample;
  sample[key];
}
Enter fullscreen mode Exit fullscreen mode

const key 에 마우스 커서를 올려보면(vscode에서) key는 다음과 같은 값을 가질 수 있는 타입이 된 것을 알 수 있다

const key = "taMin0" | "taMin1" | "taMin2" | "taMin3"

 

keyoftypeof 2 개 모두 꼭 필요한가?

이런 경우 keyof typeof object 인 경우이고, object 대신 type을 활용한다면 keyof type 으로 약간 더 간소화할 수 있다.

  const key2: keyof IAbc = 
    ('taMin' + i.toString()) as keyof IAbc;
  sample[key2];
Enter fullscreen mode Exit fullscreen mode

위의 예제에서 for 문 대신 map 을 사용해도 동일한 오류가 발생한다

Object.keys(sample).map((key, i) => {
  sample[key]
})
Enter fullscreen mode Exit fullscreen mode

역시 type assertion을 해줘야 한다.

Object.keys(sample).map((key, i) => {
  const specialKey: keyof IAbc = 
    key as keyof IAbc;
  sample[specialKey];
})
Enter fullscreen mode Exit fullscreen mode

Typescript에서 오류가 발생하지 않는 정상적인 전체 소스코드 예는 다음과 같다.

interface IAbc {
  taMin0: number;
  taMin1: number;
  taMin2: number;
  taMin3: number;
}

const sample: IAbc = {
  taMin0: 355,
  taMin1: 455,
  taMin2: 555,
  taMin3: 655,
}

for (let i=0; i<4; i++) {
  const key2: keyof IAbc = 
    ('taMin' + i.toString()) as keyof IAbc;
  console.log(sample[key2])
}

Object.keys(sample).map((key, i) => {
  const specialKey: keyof IAbc = key as keyof IAbc;
  console.log(sample[specialKey])
})
Enter fullscreen mode Exit fullscreen mode

소시적 C 언어 프로그래밍을 많이 했기 때문에 정적 타입 언어는 금방 적응하겠지 싶었으나, Typescript는 그리 만만치가 않다.

Photo by Leighann Blackwood on Unsplash

Top comments (0)