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
배열을 생성해낼 수 있게 되었다.