...
타입스크립트 객체 타입 체킹
타입스크립트는 객체 타입을 선언할 때 좀 더 엄밀한 속성 검사를 진행하게 된다.
예를 들어 다음 Avangers 라는 인터페이스 타입이 있다고 하자.
여기에는 name 키 속성 하나만 정의되어 있다.
이 인터페이스를 hero 변수 타입으로 정의하고 객체값을 대입하였다. 그런데 name 키 외에 location 키도 같이 넣었더니 오류가 뜬다.
interface Avengers {
name: string;
}
let hero: Avengers;
hero = { name: 'Captain', location: 'Pangyo' }; // Error - '{ name: string; location: string; }' 형식은 'Avengers' 형식에 할당할 수 없습니다. 개체 리터럴은 알려진 속성만 지정할 수 있으며 'Avengers' 형식에 'location'이(가) 없습니다
당연하게도 선언된 객체 타입 구조와 맞질 않으니 에러가 뜨게 되고 값 대입이 불가능하게 된다.
그런데 이번에는 { name: 'Captain', location: 'Pangyo' } 객체 값을 바로 hero 변수에 대입하지말고, 중간에 tmp 변수에 대입한뒤, tmp 변수를 hero 변수에 대입해보자.
interface Avengers {
name: string;
}
/*
// 타입 별칭으로 해도 마찬가지 이다.
type Avengers = {
name: string;
};
// 리터럴 객체 타입으로 해도 마찬가지 이다.
let hero: {
name: string;
};
*/
let hero: Avengers;
// hero = { name: 'Captain', location: 'Pangyo' };
let tmp = { name: 'Captain', location: 'Pangyo' };
hero = tmp; // 전혀 문제없이 대입 된다.
console.log(hero); // { name: 'Captain', location: 'Pangyo' }
직접 대입할때는 에러라면서 중간에 변수를 거쳐서 대입하면 에러가 아니랜다.
대체 갓난아기도 울고갈 이 해괴한 현상은 무슨 원리로 판단 되는 것일까?
초과 프로퍼티 검사 (Excess Property Checks)
객체 타입 속성을 검사하는 것을 좀더 전문 용어로 표현하자면 초과 프로퍼티 검사 라고 한다.
다음과 같이 객체 리터럴을 변수에 직접 할당할 때나 인수로 전달할 때, 초과 프로퍼티 검사 (excess property checking)를 받게 된다. 그래서 만약 객체 리터럴이 "대상 타입 (target type)"이 갖고 있지 않은 프로퍼티를 갖고 있으면, 당연하게도 에러가 발생된다.
그러나 객체를 다른 변수에 할당하게 되면, 변수 tmp 는 초과 프로퍼티 검사를 받지 않기 때문에, 컴파일러는 에러를 주지 않는 것이다.
그렇다고 해서 다음과 같이 인터페이스에 정의된 공통 객체 프로퍼티가 없으면 초과 프로퍼티 검사 회피든 뭐든 무조건 에러가 발생된다.
추가로 이 초과 프로퍼티 검사를 피할방법을 바로 뒤에서 배울 타입 단언 방법을 써도 가능하다.
하지만 특별한 경우에, 추가 프로퍼티가 있음을 확신한다면, 바로 인터페이스 기능인 문자열 인덱스 서명(string index signatuer)을 추가하는 것이 더 나은 방법일 수도 있다.
interface Avengers {
name: string;
[propName: string]: any;
}
정리하자면 이 초과 프로퍼티 검사는 왠만하면 "피하는" 방법을 시도하지 않는 것이 좋은 것이다.
하지만 메서드가 있고 상태를 가지는 등 더 복잡한 객체 리터럴에서 이 검사 회피 방법은 요긴하게 사용이 가능하긴 하다.
그러나 초과 프로퍼티 에러의 대부분은 실제 버그이기 때문에, 만약 초과 프로퍼티 검사 문제가 발생하면, 그냥 타입 정의를 수정해야 할 필요가 있다.
# 참고자료
https://typescript-kr.github.io/pages/interfaces.html
쉽게 시작하는 타입스크립트 (길벗, 2023, 캡틴판교 지음)
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.