프로그래밍풀스택 개발자

TypeScript에서 keyof 연산자는 어떻게 작동하며, 어떤 목적으로 사용되고 안전한 함수 및 API 설계에 어떤 영향을 미칩니까?

Hintsage AI 어시스턴트로 면접 통과

답변.

질문 배경

TypeScript는 처음부터 객체의 엄격한 타입화를 위해 설계되었고 JavaScript에서 예측 가능한 코드를 작성하는 데 중점을 두었습니다. 객체의 속성에 대한 안전한 접근을 보장하기 위한 도구 중 하나가 TypeScript 2.1에서 등장한 keyof 연산자입니다. 이 연산자는 선언된 객체 타입에서 사용 가능한 문자열(및 심볼) 키의 집합을 나타내는 타입을 생성할 수 있게 해줍니다.

문제점

순수 JavaScript에서는 객체의 속성을 어떤 문자열로든 요청할 수 있으며, 오류가 발생하면 undefined 또는 실행 중에만 발견되는 오류가 발생합니다. 엄격한 타입화가 없으면 오타를 내거나 리팩토링 중에 키 문자열 업데이트를 잊기 쉽습니다. 또한 특정 객체나 타입의 유효한 키만 허용하는 함수를 작성해야 하는 경우가 많습니다.

해결책

keyof 연산자는 타입의 모든 키로부터 유니온 타입을 생성합니다. 이를 통해 허용된 키를 제한하고 API의 안전성을 높이며(예: getter/setter 함수의 경우) 범용 유틸리티 타입을 만들 수 있습니다.

코드 예시:

type User = { name: string; age: number; active: boolean }; type UserKey = keyof User; // "name" | "age" | "active" function getProp<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } const user: User = { name: 'Tom', age: 33, active: true }; const age = getProp(user, 'age'); // age는 number 타입

주요 특징:

  • 객체 구조에 따라 "키" 타입을 선언할 수 있습니다.
  • 속성의 get/set 함수가 최대한 타입 안전하게 됩니다 — 오타와 존재하지 않는 키가 제외됩니다.
  • TypeScript 2.7 이상부터 심볼 속성에서도 작동합니다.

숨겨진 질문들.

배열에서 keyof가 반환하는 것은 무엇이며 인덱스를 얻을 수 있습니까?

배열에 대해 keyof는 배열이 실제로 JavaScript에서 객체로서 보유하고 있는 키 타입을 반환합니다. 일반적으로 인덱스 문자열과 배열의 특별한 속성이 포함됩니다.

코드 예시:

type A = keyof number[]; // "length" | "toString" | "pop" | ... | number

keyof가 유니온 타입의 키를 반환할 수 있습니까?

네, 유니온 타입의 keyof는 두 객체의 키 교차 집합을 반환하며, 합집합이 아닙니다.

코드 예시:

type A = {a: string, b: number } type B = {b: number, c: boolean } type C = keyof (A | B); // "b"

객체 속성이 선택적일 경우 어떻게 됩니까? keyof는 "?"를 지원합니까?

네, 선택적 속성도 결과 키 타입에 포함되지만, 이는 런타임에서 객체에 속성이 반드시 존재해야 한다는 것을 의미하지는 않습니다.

코드 예시:

type D = { a: string; b?: number }; type DK = keyof D; // "a" | "b"

일반적인 오류 및 안티 패턴

  • 키로 keyof 대신 상수 문자열을 사용하는 것은 타입 손실입니다.
  • 유니온에 대한 keyof가 합집합을 반환한다고 생각하는 것은 잘못된 것입니다.
  • keyof가 명시적으로 선언된 키만 고려되고 상속된 키는 무시된다고 예상하는 것은 잘못된 것입니다.

실생활 예제

부정적 사례

getProperty(obj, key) 함수를 문자열 타입의 키로 작성하고 존재하지 않는 키를 호출할 때, 오류는 런타임에만 발생합니다.

장점:

  • 범용 코드입니다.

단점:

  • 컴파일 단계에서 검사하지 않아 리팩토링 시 오류가 발생할 수 있으며, 오타에 취약합니다.

긍정적 사례

제네릭을 사용: getProperty<T, K extends keyof T>()에서 key 타입은 구조의 키로 엄격하게 제한됩니다.

장점:

  • 절대적인 타입 안전성, 오타나 키 오류는 발생하지 않습니다.

단점:

  • 코드가 약간 복잡해지며 제네릭이 초보자에게 항상 이해되지는 않습니다.