
keyof 연산자는 객체 타입에서 객체의 키 값들을 숫자나 문자열 리터럴 유니언으로 생성한다.
아래의 타입 P는 'x' | 'y'와 동일한 타입이다.
type Point = { x: number; y: numer;};
type P = keyof Point;
요약하자면, 자바스크립트에서의 typeof 는 변수의 타입을 반환하고, keyof 는 객체 또는 인터페이스의 키 값을 타입으로 반환하는 것이다.
만약 타입이 string이나 number 인덱스 시그니처를 가지고 있다면, keyof 는 해당 타입을 리턴한다.
type Arrayish = { [n: number]: unknown };
type A = keyof Arrayish; // number;
type Mapish = { [k: string]: boolean };
type M = keyof Mapish; // string | number
여기서 주목할 점은 M의 타입이 string | number 라는 점이다.
Javascript 객체 키는 항상 문자열을 강제하기 때문에 obj[0]은 obj['0']과 동일하다
typescript에서는 number 키도 자동으로 string으로 변환되기 때문에 안전하게 number | string 으로 확장해서 보는 것이다.
그래서 type Arrayish = { [n: number]: unknown }; 이긴 하지만 n에 '1'과 같은 문자열 숫자 키도 허용된다.
keyof 타입은 매핑된 타입과 함께 사용할 때 특히 유용하다.
인터페이스를 정의하고 keyof 를 사용하여 해당 인터페이스의 모든 속성 이름을 가져올 수 있다.
interface Person {
name: string;
age: number;
address: string;
}
type PersonKeys = keyof Person;
PersonKeys는 "name" | "age" | "address" 라는 문자열 리터럴 유니온 타입이 된다.
이렇게 생성된 문자열 유니온 타입을 사용하여 객체의 속성 이름을 동적으로 참조하거나 검사할 수 있다.
type Filter = {
size: string[];
breed: string[];
}
const [selectedFilter, setSelectedFilter] = useState<Filter>({
size: [],
breed: [],
});
const handleFilterSelect = (filterKey: keyof Filter, filterName: string) => {
const updatedFilter = { ...selectedFilter };
// 이미 배열에 저장되어 있는 filter 값인 경우 배열에서 제거
if(selectedFilter[filterKey].includes(filterName)) {
updatedFilter[filterKey] = updatedFilter[filterKey].filter((name) => name !== filterName));
selectedFilter(updatedFilter);
return;
}
// 배열에 저장되어 있지 않은 filter 값인 경우 배열에 추가
updatedFilter[filterKey].push(filterName);
setSelectedFilter(updatedfilter);
}
const handlePrintOptionButtonClick = (groupIndex: number, buttonIndex: number) => {
...
const selectedKey = ButtonTitleKey[printMod as keyof typeof ButtonTitleKey][groupIndex];
}
keyof typeof 를 사용해 객체의 키 값을 타입으로 가져왔다.
-> typeof ButtonTitleKey 는 ButtonTitleKey 객체의 타입을 가져오고, keyof 를 사용해 해당 객체의 모든 키 값을 가져온다.
그렇다면 아래와 같은 상황에서는 어떻게 사용해야 할까?
const person = {
name: 'jiwoo',
age: 10,
}
console.log(typeof person); // 'object'
typeof 만 사용했을 경우, 이런식으로 'object'라는 타입을 반환하게 되고, keyof 를 사용하면 해당 객체의 키 값을 유니온 타입으로 반환한다고 했는데 어쩔 때 같이 사용해야 할까?
const bmw = { name: 'BMW', power: '1000hp' };
type CarLiteraltype = keyof typeof bmw;
let carPropertyLiteral: CarLiteraltype;
carPropertyLiteral = 'name' // OK
carPropertyLiteral = 'power' // OK
carPropertyLiteral = 'anyOther' // Error...
위 예시처럼, 미리 interface 등으로 타입 지정이 되어 있지 않고 값만 할당되어 있는 경우 object에서 바로 사용하고 싶은 경우에 typeof와 keyof를 같이 사용하여 해당 객체의 키 값으로 이루어진 유니온 타입을 얻을 수 있다.