🛠️ Intro
logPerson함수에서 발생하는 type error를 수정해라.
logPerson함수의 인자로는 User Type 또는 Admin Type이 들어갈 수 있다
.
이 때 occupation property는 User Type에 있고 role property는 Admin Type에 존재한다.
문제
에러가 나는 곳에 마우스를 올려보면 typescript가 어떤 불만을 토로하는 지 알 수 있다.
이는 Person Type은 User 또는 Admin이라는 type을 가지는데 Admin Type에는 role이라는 poperty가 정의되어있지만, User Type에는 role property가 정의되어있지 않다라는 불만이다.
좀 더 자세하게 설명하자면,
User와 Admin의 공통 properties
1. name
2. ageUser 또는 Admin만 가지는 property
1. User -> occupation property를 가짐
2. Admin -> role property를 가짐
위의 같이 User Type인지 Admin Type인지에 따라서 occupation 또는 role
property의 존재 유무가 갈리게 된다. 따라서, typescript에게 분기점에 따라 정확하게 어떤 타입인지 추려줘야하는데 이를 type narrowing
이라고 한다. 여러 종류의 type이 들어올 수 있는 상황에서 어떤 타입인지 특정해주는 것을 말한다.
근데 여기서 육안적으로 봤을 때 맥락상 좀 헷갈릴 수 있다. 맥락상으로는 말도 되며 typescript없이 javascript만 코드를 작성했을 때 가능하기 때문이다.
💡 궁금증
처음에 본인은 role이라는 property가 Admin Type에만 존재하며 이를 logPerson함수의 인자로 넣어주면if(person.role) = true가 되어 if문 안에서 Admin Type이라고 추론할 수 있는 거 아닌가....?
라고 생각했다.다시 생각해보니 애초에 if문 안의 값을 평가할 때 person에 접근했는데 role이라는 것이 있을 지 없을 지에 대한 오류인 것이다. 따라서, typescript는 접근 전에 type을 narrowing해줘야 한다는 결론에 이르렀다. 여기서 javascript는 compile시 알 수 있어 없는 property에도 접근을 허용하지만, typescript는 그렇지 않다는 것이다.
분기점에 따라 person이 어떤 type을 가지는지 특정(narrowing)해주어야 한다. 이는 in
keyword를 이용한 In Operator Narrowing을 통해서 User인지 Admin인지 type을 좁힐 수 있다.
javascript에서in
keyword는 객체 안에 key값 유무를 해싱 덕분에 O(1) 시간 복잡도로 key값의 탐색을 제공한다.
사실상, typescript만이 아닌 javascript에도 존재하는 문법이며, typescript에서는 이 in
keyword를 이용하면 Type을 특정할 수 있게 지원해주는 점이 javascript와 다른 점 같다.
// AS-IS
export function logPerson(person: Person) {
let additionalInformation: string;
if (person.role) { // ❌
additionalInformation = person.role;
} else {
additionalInformation = person.occupation;
}
console.log(` - ${person.name}, ${person.age}, ${additionalInformation}`);
}
// TO-BE
export function logPerson(person: Person) {
let additionalInformation: string;
if ('role' in person) { // ✅
additionalInformation = person.role;
} else {
additionalInformation = person.occupation;
}
console.log(` - ${person.name}, ${person.age}, ${additionalInformation}`);
}
role property는 Admin에만 존재
하므로 if문에는 person에 role이란 속성이 존재하냐???
에 대한 값이 참일 시 typescript는 if문 안에서는 person이 Admin Type으로 특정할 수 있다.
해결!!
이 문제를 풀다보니까 위에 내가 던졌던 궁금증에 대해서 javascript로는 Admin type임을 확신할 수 있다. 이를 근거해 if('role' in person)
을 이용하지 않고 각 person에 대해서 (person as Admin).role
또는 (person as User).occupation
를 이용하여 타입 단언을 하는 사람을 봤다. 이렇게 하면 코드의 양도 많아질 뿐 더러 분기처리를 잘못했을 때 오류가 발생할 수 있다고 생각하기 때문이다. 사람은 실수하는 동물이므로 개인적으로는 좋지 않은 방법이라고 생각한다.
type assertion 예시
export function logPerson(person: Person) {
let additionalInformation: string;
if ((person as Admin).role) { // 지양
additionalInformation = (person as Admin).role; // 지양
} else {
additionalInformation = (person as User).occupation; // 지양
}
console.log(` - ${person.name}, ${person.age}, ${additionalInformation}`);
}