객체 키 타입의 유니온 추출 및 활용
상수로 이용하려는 이미 정의된 객체 데이터를 타입스크립트로 다루다보면 가끔씩 불편한 상황을 마주하곤 한다.
나의 경우에는 객체 데이터 자체를 타입으로써 이용하고 싶은데 타입스크립트가 너무 빡빡하게 굴 때 종종 심기가 불편해진다. 가끔은 객체 타입을 모두 손수 지정해버리고 싶다는 충동이 들 때마저 있다.
물론 왕도는 없는듯 하다. 유지보수가 다소 어려워질것을 감안하고 객체의 타입을 모두 손수 지정해서 사용할 것인지, 아니면 특정 객체를 100% 신뢰한 상태에서 타입을 뻗어낼 것인지는 상황에 따라 판단하면 된다. 하지만 두 방법 모두 잘 알고 있기는 해야할 것이다.
객체 타입을 모두 손수 지정하는 것은 어렵지않은 단순 노가다이므로,
이 글에서는 객체 타입을 프로퍼티로 각각 분리하여 운용하는 방법에 대해 기술할 것이다.
객체의 구성
객체는 키와 밸류로 구성되어 있다는 것은 타입스크립트를 배우는 사람들은 누구나 알 것이다.
키와 밸류가 합쳐져 프로퍼티를 구성한다.
const obj = {
키: "밸류"
}
프로퍼티를 온전하게 사용한다고 함은 객체의 키를 통해 밸류에 접근할 수 있다는 것을 의미한다.
타입스크립트도 동일하다. 객체 타입의 키를 뽑아낼 수 있다면 객체 타입을 자유자재로 이용할 수 있다.
그렇다면 객체 타입의 키는 어떻게 뽑아낼 수 있을까?
타입스크립트 typeof 연산자
타입스크립트는 변수, 함수, 객체의 타입을 추론하는 typeof 연산자를 제공한다.
자칫 잘못하면 자바스크립트의 typeof 연산자와 헷갈릴 수 있는데 둘은 아예 다른 연산자임을 기억하자.
- 자바스크립트의 typeof 연산자는 표현식 컨텐스트에서 사용하고, 특정 문자열을 리턴한다.
- 타입스크립트의 typeof 연산자는 컴파일 과정에서 변수, 함수, 객체의 타입만 추론한다.
다시 타입스크립트의 type 연산자에 초점을 맞춰보자.
typeof 연산자를 사용하는 방법은 아래와 같다.
1. 변수 타입 추론
const num = 10;
type NumType = typeof num; // number
2. 객체 타입 추론 ★
const person = {
name: "John",
age: 30,
};
type PersonType = typeof person; // { name: string, age: number }
3. 함수 타입 추론
function greet(name: string): string {
return `Hello, ${name}!`;
}
type GreetType = typeof greet; // (name: string) => string
예제를 보면 알 수 있듯이 typeof 연산자를 이용하면 컴파일 타임에 존재하는 변수, 객체, 함수의 타입을 추론할 수 있다.
객체의 타입을 뽑아냈다면 그 객체의 타입에서 키 타입도 따로 뽑아낼 수 있다.
keyof 연산자
keyof 연산자는 객체 타입의 모든 키를 유니온 타입으로 추출하는 역할을 한다. 자바스크립트에는 없는, 오로지 타입스크립트에만 존재하는 연산자이므로 typeof 처럼 헷갈릴 일은 없을 것이다.
추론된 객체 타입이 있다면 그 타입에서 키를 유니온으로 뽑아낸다는 말은 무슨 말일까?
아래 코드를 보자.
const obj = {
name: "John",
age: 30,
city: "New York",
};
type Keys = keyof typeof obj; // "name" | "age" | "city"
typeof 연산자로 뽑아낸 obj의 객체 타입에 keyof 연산자를 이용해 객체의 키 값만 뽑아내고 있다.
여기까지 이해했으면 typeof와 keyof는 자유자재로 이용할 수 있을 것이다.
마지막으로, 실전에서 어떻게 활용하는지에 대해 공유하고 포스팅을 마무리할까 한다.
<실전>
요구사항
// constants.ts
export const slugIntro = {
test1: {
title: '연습용 체크 프로세스1',
introduce: '당신은 남자의 소울푸드를 좋아하십니까?',
},
test2: {
title: '연습용 체크 프로세스2',
introduce: '소주십니까? 맥주십니까? 소맥이십니까?',
},
}
심리상태 : 나는 slugIntro 객체를 상수로써 이용하고 싶다. 객체에 일일히 타입을 지정해주기는 귀찮다. 그냥 이미 존재하고 있는 있는 객체로 모든 타입 지정을 쇼부보고 싶다.
필수 요구사항 : slugIntro 객체에서 한 개의 프로퍼티만 표현하는 타입을 만들어야 한다.
해결
1. 객체의 타입과 키 타입을 분리해놓는다.
// types.ts
import { slugIntro } from '@/constants/check-list'
type KeyOfObject<T> = keyof T
export type CheckSlugKey = KeyOfObject<typeof slugIntro>
- keyof typeof [객체명] 이 불편하다면 위처럼 제네릭을 만들어서 코드를 정돈할 수 있다.
2. 방금 분리해놓은 키 타입을 typeof slugIntro로 뽑아낸 객체 타입의 접근 용도로 사용한다.
export type SelectedSlugIntro = (typeof slugIntro)[CheckSlugKey]
결론
타입 지정때문에 생기는 문제들도 타입스크립트의 기본 문법들을 보면서 찬찬히 생각해보면 결국 쉽게 풀린다. 타입스크립트 자체가 프로그램 구동에 주는 영향이 없다보니 등한시하는 경우가 있는데, 그러면 안된다는 것을 요즘 느끼고 있다.
타입설정을 잘 해놓으면 유지보수나 기능 추가를 할 때 굉장히 편하다. 반대로 타입 지정을 잘 해놓지 못했다면 추가적인 작업에 많은 리소스를 들이게 될 것이다. 미래시의 내가 칼퇴를 하려면 타입의 설계는 필수다. 100% 완벽하게는 아니더라도.
'Typescript' 카테고리의 다른 글
재귀로 객체 내 모든 키값을 추출하는 타입 만들기 (0) | 2024.04.08 |
---|---|
유틸리티 타입 (Parameters) (0) | 2023.11.21 |
유틸리티 타입 (Partial, Required, Record) (0) | 2023.10.27 |
keyof typeof typesomething (0) | 2023.09.05 |
React 컴포넌트에 타입스크립트 적용 (0) | 2023.09.05 |