[TypeScript] 인덱스 액세스 타입(Indexed Access Types): 객체 속성 정밀 추출

인덱스 액세스 타입이란

인덱스드 액세스 타입은 `Type["property"]` 문법으로 객체 타입에서 특정 속성의 타입을 가져옵니다.

interface User {
  id: string;
  name: string;
  active: boolean;
}

type UserName = User["name"]; // string

const getName = (user: User): UserName => user.name;
const user: User = { id: "u1", name: "지훈", active: true };
console.log(getName(user)); // 출력: 지훈

`User["name"]`으로 `name` 속성의 타입(`string`)을 추출.

유니언과 keyof 활용

인덱스 타입 자체가 타입이므로, 유니언이나 `keyof`를 결합해 더 복잡한 타입을 만들 수 있습니다.

유니언으로 여러 속성 참조

type UserInfo = User["id" | "name"]; // string

const displayInfo = (key: "id" | "name", data: User): UserInfo => data[key];
console.log(displayInfo("id", user));   // 출력: u1
console.log(displayInfo("name", user)); // 출력: 지훈

keyof로 모든 속성 타입

type UserValue = User[keyof User]; // string | boolean

function printValue(value: UserValue): void {
  console.log(`값: ${value}`);
}

printValue(user.id);      // 출력: 값: u1
printValue(user.active);  // 출력: 값: true

유니언 타입으로 제한

type StatusOrName = "active" | "name";
type RestrictedUser = User[StatusOrName]; // string | boolean

const checkField = (field: StatusOrName, u: User): RestrictedUser => u[field];
console.log(checkField("active", user)); // 출력: true

존재하지 않는 속성 오류

// type Wrong = User["email"]; // 오류: 'email'은 User에 없음

배열 요소 타입 추출

숫자 인덱스(`number`)로 배열 요소의 타입을 가져올 수 있으며, `typeof`와 결합하면 더욱 유용합니다.

const fruits = [
  { type: "apple", count: 5 },
  { type: "banana", count: 10 },
];

type Fruit = typeof fruits[number]; // { type: string; count: number }

const getFruitCount = (fruit: Fruit): number => fruit.count;
console.log(getFruitCount(fruits[0])); // 출력: 5

type FruitCount = Fruit["count"]; // number
const totalCount: FruitCount = fruits[1].count;
console.log(totalCount); // 출력: 10

변수 참조의 한계

값(변수)은 인덱스로 사용할 수 없습니다

const prop = "name";
// type Error = User[prop]; // 오류: 값은 타입으로 사용 불가

해결: 타입 별칭 사용

type Prop = "name";
type NameType = User[Prop]; // string

const extractName = (u: User): NameType => u.name;
console.log(extractName(user)); // 출력: 지훈

동적 키로 속성 정리

interface Config {
  apiKey: string;
  timeout: number;
  retries: number;
}

type ConfigField = keyof Config; // "apiKey" | "timeout" | "retries"
type ConfigValue = Config[ConfigField]; // string | number