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)