타입스크립트에서 Object.keys() 타입 지정

nearworld·2023년 3월 22일
2

typescript

목록 보기
22/28
const obj = {
  name: 'kim',
  age: 30
};

Object.keys(obj);
// 값: ['name', 'age']
// type: string[]

Object.keys()는 객체의 키값들을 배열에 집어넣고 그 배열을 리턴해주는 메서드.

위 메서드는 아래와 같은 패턴으로 자주 쓰였다.

const obj = {
  home: 'welcome home',
  faq: 'frequently asked questions'
};

// 코드 생략
<ul>
  {Object.keys(obj).map((key, index) => (
    <li>{obj[key]}</li>
  )}
</ul>

위 코드를 작성해보니 에러가 발생하는 것을 발견했다.

에러 내용이 아래와 같이 나왔다.

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{ home: string; faq: string; }'.
  No index signature with a parameter of type 'string' was found on type '{ home: string; faq: string; }'.ts(7053)
const obj = {
  home: 'welcome home',
  faq: 'frequently asked questions'
};
type Obj = typeof obj;
// { home: string, faq: string}

obj의 키값들은 타입이 home, faq로 딱 지정되어있는데 string 타입을 키값으로 쓰려하니 어떤 키값을 적용하려고 하는지 알 수 없다. 그러다보니 모든 키에 해당하는 값을 허용하기 위해 any로 암묵적 추론을 하는 것 같다.

위 코드에서 obj의 타입 Obj를 보면 키 타입이 string이 아닌 home faq로 되어있다.
결국 index signature를 지정해주거나 home faq 타입을 사용해야한다.
home, faq 만 인덱스 값으로 사용하는 것이 더 안전하다고 생각한다.

그러기 위해서는 obj 객체에서 키값들을 추출하고 타입으로 만들어야한다.

const obj = {
  home: 'welcome home',
  faq: 'frequently asked questions'
};
const typedKeys = Object.keys(obj) as Array<keyof typeof obj>;

// 코드 생략
<ul>
  {typedKeys.map((key, index) => (
    <li>{obj[key]}</li>
  )}
</ul>

이제 key 파라미터는 string 타입이 아니라 home faq 타입 중 하나로 결정되기 때문에 index관련 에러가 없이 객체 프로퍼티 값에 접근이 가능해졌다.

이렇게 타이핑된 객체 키 배열을 만드는 코드를 추상화하여 여러 객체에서 사용하게 하려면 함수를 만들고 제네릭을 붙여쓰면 가능하다.

const getKeys = <T extends Object>(obj: T): Array<keyof T> => Object.keys(obj) as Array<keyof T>;

const temp = {
  home: 'welcome home',
  faq: 'frequently asked quesetions'
};
const typedKeys = getKeys(temp);

// 코드 생략
<ul>
  {typedKeys.map((key, index) => (
    <li>{obj[key]}</li>
  )}
</ul>

제네릭으로 인해 다양한 객체에 대하여 typedKeys 배열을 생성해낼 수 있게 되었다.

profile
깃허브: https://github.com/nearworld

0개의 댓글