객체에 동적 변수를 key 값으로 하여 접근하기 위해 대괄호 표기법을 사용했을 때, 이러한 타입 에러가 발생했다.
실제 코드는 훨씬 복잡하기 때문에 간략한 예시로 정리
const obj = {
one: "uno",
two: "dos",
three: "tres",
};
for (const k in obj) {
const v = obj[k];
}
obj에 명시된 타입이 없기 때문에 엘리멘트는 암시적으로 'any' 타입이다.
k의 타입은 string인 반면, obj 객체에는 ‘one’, ‘two’, ‘three’ 세 개의 키만 존재한다.
k와 obj 객체의 키 타입이 서로 다르게 추론되어 오류가 발생한 것이다.
이 오류를 해결하기 위해서는 k의 타입을 더욱 구체적으로 명시해야 한다.
이때 두가지 방법이 있다.
1. 인덱스 시그니처 추가
interface Obj {
[key: string] : string
}
const obj: Obj = {
one: "uno",
two: "dos",
three: "tres",
};
for (const k in obj) {
const v = obj[k];
}
key에 대한 타입도 명시를 해줌으로써 해결
근데 이 방법으로 해결이 되지 않는 경우가 있다.
2. 타입 어설션 (Type Assertion)
이때 사용할 수 있는 것이 keyof 이다.
keyof 타입 연산자는 객체 타입에서 객체의 키 값들을 숫자나 문자열 리터럴 유니언을 생성한다.
let k: keyof typeof obj;
for (k in obj) {
console.log(k);
}
// one
// two
// three
(사실 타입 정의 안해줘도 출력 값은 똑같다. 타입 에러가 날 뿐..)
keyof typeof obj는 obj의 key 값들로 구성된 문자열 리터럴 유니언을 생성하고, k의 타입이 그것임을 명시해준 것이다.
결과적으로 k는 타입을 명시해줌으로써 타입 안정성이 생겼다.
const obj = {
one: "uno",
two: "dos",
three: "tres",
};
for (const k in obj) {
const v = obj[k as keyof typeof obj];
}
그렇다면 첫 번째 코드에서 k 타입이 string으로 추론된 이유는?
▶ 타입스크립트에서 for ... in 루프를 사용하여 객체의 프로퍼티를 순회할 때, 루프 변수에 대한 타입 추론은 현재 존재하는 프로퍼티 키 뿐만 아니라 객체가 가질 수 있는 모든 프로퍼티 키를 고려한다. 그렇기 때문에 그 가능성의 합집합인 string 타입으로 k의 타입을 추론하는 것이다.
결론
아무런 처리를 해주지 않아도 타입스크립트는 k의 타입을 string으로 추론해주기 때문에 동작은 문제없이 된다.
하지만 타입 안정성을 위해 명확한 타입을 지정해주라는 타입 경고가 나오는 것이다.
[ 참고 자료 ]
댄 밴더캄, 『 이펙티브 타입스크립트 』 : 아이템54 객체를 순회하는 노하우
'Typescript' 카테고리의 다른 글
Typescript 제네릭(generic)이란? (0) | 2024.09.26 |
---|---|
인덱스 시그니처 (0) | 2024.05.14 |
Type of emit value is always 'any' with new style defineEmits (0) | 2024.03.27 |
Typescript 인터페이스 네이밍 규칙 어떻게 할까? | 접두사 I를 사용하면 안 되는 이유 (1) | 2024.03.27 |
@input event의 타입 (0) | 2024.03.27 |