타입스크립트 keyof typeof

서성원·2025년 4월 27일

타입스크립트

목록 보기
2/2
post-thumbnail

사용법

객체를 선언하고 그 key를 타입으로 쓰고 싶다면 무조건 as const를 붙이고 keyof typeof를 쓴다.

1. 버튼 타입 제한

const BUTTON_TYPES = {
  primary: 'Primary Button',
  secondary: 'Secondary Button',
  danger: 'Danger Button',
} as const;

type ButtonType = keyof typeof BUTTON_TYPES;
// ButtonType = 'primary' | 'secondary' | 'danger'

interface ButtonProps {
  type: ButtonType;
}

const Button = ({ type }: ButtonProps) => {
  return <button>{BUTTON_TYPES[type]}</button>;
  • 버튼 타입 prop은 'primary' | 'secondary' | 'danger'만 가능하다.
  • 실수로 'Third' 를 넣으면 컴파일 에러가 난다.

2. API 요청 타입 강제

const API_ENDPOINTS = {
  getUser: '/api/user',
  getPosts: '/api/posts',
  getComments: '/api/comments',
} as const;

type ApiType = keyof typeof API_ENDPOINTS;
// 'getUser' | 'getPosts' | 'getComments'

function fetchApi(api: ApiType) {
  return fetch(API_ENDPOINTS[api]);
}
  • fetchApi('getPosts') 처럼 사용한다.
  • 없는 API 이름 쓰면 에러 발생.

3. 테마 설정

const THEMES = {
  light: 'Light Mode',
  dark: 'Dark Mode',
  system: 'System Default',
} as const;

type ThemeType = keyof typeof THEMES;
// 'light' | 'dark' | 'system'

function setTheme(theme: ThemeType) {
  console.log(`Setting theme to ${THEMES[theme]}`);
}
  • setTheme('light') or setTheme('dark')

4. key 매핑해서 타입 변환하기

키를 이용해 새로운 타입 만들기

const THEMES = {
  light: 'Light Mode',
  dark: 'Dark Mode',
  system: 'System Default',
} as const;

type ThemeValue = {
  [K in keyof typeof THEMES]: string;
{
  light: string;
  dark: string;
  system: string;
}

➡️ ThemeValues 타입의 모습입니다.
객체의 키들을 순회하며 새로운 타입을 만들 수 있으며, 이것을 Mapped Type 이라 합니다.

5. 키 값(value)에 따라 타입 달리하기

const API_ENDPOINTS = {
  getUser: '/api/user',
  getPosts: '/api/posts',
  deletePost: null,
} as const;

// value가 null이면 optional, 아니면 required로
type ApiFunctions = {
  [K in keyof typeof API_ENDPOINTS]: type of API_ENDPOINTS[K] extends string
  	? () => Promise<void>
    : never;
};
  • extends는 타입 상속과 타입 검사에 둘 다 사용됩니다. 여기서는 string인지 검사합니다.
  • 'getUser', 'getPosts'는 () => Promise 타입으로 매핑
  • 'deletePost'는 never로 매핑

언제 사용할까?

  • 정해진 키들만 쓰도록 할 때
  • props 안전하게 하고 싶을 때
  • 객체의 키들을 타입으로 안전하게 뽑아내고 싶을 때

string 리터럴 사용하면 안 되나?

type ColorKey = 'red' | 'blue' | 'green';

-> 리터럴로 직접 쓰기.

  const COLORS = {
  red: '#ff0000',
  blue: '#0000ff',
  green: '#00ff00',
  yellow: '#ffff00',  // 새로운 색 추가
} as const;

여기서 만약 새로운 프로퍼티를 추가해야 하는 상황이라면?

// 기존
type ColorKey = 'red' | 'blue' | 'green';

// yellow 추가했으니까 여기도 수정해야 함
type ColorKey = 'red' | 'blue' | 'green' | 'yellow';

객체를 바꿀 때마다 타입도 수동으로 수정해야 합니다.
이것은 매우 비효율적입니다.

keyof typeof 쓰기

type ColorKey = keyof typeof COLORS;  

객체가 바뀌면 타입도 자동으로 따라갑니다.

프로젝트에 적용해보기

  1. 믹스패널 track 이벤트를 클릭함수 내에 적용해야 한다.
  2. 데스크탑 home 버튼과 모바일 home버튼에 각각 다른 이벤트를 적용해야 한다.

trackEvent 타입

 const trackEventNames = {
  desktop: 'Home Button Clicked',
  mobile: 'Mobile Home Button Clicked',
} as const; 

Click 함수에 매개변수로 전달하기

const handleHomeClick = (device: keyof typeof trackEventNames) => {
    navigate('/');
    setKeyword('');
    setInputValue('');
    trackEvent(trackEventNames[device]);
};

마치며

프로젝트를 하면서 타입스크립트를 그때그때 배우고 있지만 항상 새롭습니다. 그래도 그때그때 배우는게 기억에 제일 잘 남는 것 같아요. 피드백은 언제나 환영입니다!

profile
FrontEnd Developer

0개의 댓글