개인의 기록
  • 소개
  • 프로젝트
  • 글
  • 링크

© 2026 newgirok

← 글 목록

keyof와 typeof — 타입에서 타입을 만드는 연산자

2025년 11월 22일
TypeScriptkeyoftypeof타입타입 연산자

TypeScript에서 타입을 처음부터 작성하지 않고, 기존 타입이나 값에서 새 타입을 파생하는 방법이 있습니다. keyof와 typeof는 이 파생 작업의 핵심 연산자입니다.

keyof

객체 타입의 모든 키를 유니온 타입으로 반환합니다.

interface User {
  id: number;
  name: string;
  email: string;
}

type UserKey = keyof User;
// "id" | "name" | "email"

활용 — 안전한 프로퍼티 접근

keyof를 제네릭 제약과 함께 쓰면, 존재하는 키만 허용하는 함수를 만들 수 있습니다.

function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
  return obj[key];
}

const user = { id: 1, name: "철수", email: "chulsoo@example.com" };

const name = getProperty(user, "name");   // string
const id   = getProperty(user, "id");     // number
getProperty(user, "age");                 // 오류: "age"는 User의 키가 아닙니다

반환 타입 T[K]는 실제 프로퍼티의 타입이 됩니다. "name"을 요청하면 string, "id"를 요청하면 number가 반환됩니다.

인덱싱 접근 타입(Indexed Access Type): T[K] 형태로 타입의 특정 프로퍼티 타입을 가져오는 문법.

배열 인덱싱

배열 타입에 keyof를 쓰면 숫자 인덱스와 배열 메서드 이름을 포함한 유니온이 나옵니다.

type Arr = string[];
type ArrKeys = keyof Arr; // number | "length" | "push" | "pop" | ...

배열 원소의 타입을 꺼낼 때는 T[number]를 씁니다.

type Colors = ["red", "green", "blue"];
type Color = Colors[number]; // "red" | "green" | "blue"

typeof

값(변수, 함수, 객체)에서 타입을 추출합니다. 타입 선언 없이 작성한 값에서 타입을 파생할 때 유용합니다.

const config = {
  host: "localhost",
  port: 3000,
  debug: true,
};

type Config = typeof config;
// { host: string; port: number; debug: boolean }

별도 타입 선언 없이 config를 기준으로 타입을 정의할 수 있습니다. 이후 config의 구조가 바뀌면 Config도 자동으로 갱신됩니다. 타입 위치에서 쓰이는 typeof는 값의 타입을 가져오며, 런타임의 typeof(문자열 반환)와 구분됩니다.

함수에서 타입 추출

function createUser(name: string, age: number) {
  return { name, age, id: Math.random() };
}

type CreateUserFn = typeof createUser;
// (name: string, age: number) => { name: string; age: number; id: number }

type UserResult = ReturnType<typeof createUser>;
// { name: string; age: number; id: number }

keyof + typeof 조합

값에서 타입을 꺼내고, 그 키를 추출하는 조합입니다. 상수 객체를 타입의 기준으로 삼을 때 자주 씁니다.

const COLORS = {
  red: "#FF0000",
  green: "#00FF00",
  blue: "#0000FF",
} as const;

type ColorKey = keyof typeof COLORS;
// "red" | "green" | "blue"

type ColorValue = typeof COLORS[ColorKey];
// "#FF0000" | "#00FF00" | "#0000FF"

function getColor(key: ColorKey): string {
  return COLORS[key];
}

getColor("red");    // 정상
getColor("yellow"); // 오류: '"yellow"'는 'ColorKey'에 할당할 수 없습니다

as const: 객체나 배열을 리터럴 타입으로 추론하게 하는 단언. 프로퍼티 값을 리터럴 타입으로 좁히고 readonly로 만들어줍니다.

열거형 대안 패턴

TypeScript의 enum 대신 as const 객체 + keyof typeof를 쓰는 패턴입니다. 런타임 코드가 없고 트리 셰이킹에 유리합니다.

const Direction = {
  Up: "UP",
  Down: "DOWN",
  Left: "LEFT",
  Right: "RIGHT",
} as const;

type Direction = typeof Direction[keyof typeof Direction];
// "UP" | "DOWN" | "LEFT" | "RIGHT"

function move(dir: Direction) {
  console.log(dir);
}

move(Direction.Up);  // 정상
move("UP");          // 정상
move("up");          // 오류

keyof와 typeof를 개별로 써도 유용하지만, 조합하면 코드에 이미 존재하는 값으로부터 타입을 파생하는 강력한 패턴이 됩니다. 타입과 값을 이중으로 관리할 필요 없이, 값을 수정하면 타입도 자동으로 따라갑니다.

← 이전 글유틸리티 타입 — 기존 타입을 변환하는 내장 도구
다음 글 →맵드 타입 — 기존 타입의 모든 프로퍼티를 변환하기