...
Non-null assertion operator
자바스크립트를 포함한 대부분 프로그래밍 언어에서 느낌표(!)는 주로 False를 의미하는 연산자로 사용된다.
하지만 타입스크립트에서 변수 앞이 아닌, 뒤에 느낌표(!)를 사용하면 기발한 용도로 사용할 수 있는데, 피연산자가 Nullish(null이나 undefined) 값이 아님을 단언할 수 있다.
이를 Null이 아닌 단언 연산자(Non-null assertion operator) 또는 확정 할당 어선셜(Definite Assignment Assertions) 이라고도 부른다. Null이 아닌 어선셜 연산자는 피연산자가 null이 아니라고 컴파일러에게 전달하여 일시적으로 Null 제약조건을 완화시킨다.
당최 무슨말인지 모를것이다. 😪 이해를 돕기위해 다음 코드를 살펴보자.
다음과 같은 자바스크립트 코드가 있다. menu-item 이라는 엘리먼트를 불러와 그의 속성인 innerHTML을 가져온다.
하지만 만일 menu-item 이라는 엘리먼트가 존재하지 않을때 아무리 자바스크립트라 해도 바로 에러를 내뿜는다.
그래서 보통 ?. 연산자를 통해 해결한다. (값은 undefined지만 에러는 안난다)
document.querySelector('.menu-item').innerHTML;
// menu-item 엘리먼트가 없을 경우를 대비해 이런식으로 && 연산자를 쓰거나
document.querySelector('.menu-item') && document.querySelector('.menu-item').innerHTML
// 다음과 같이 ? 로 해결할 수 있다.
document.querySelector('.menu-item')?.innerHTML;
그럼 타입스크립트는 어떻게 해결할까?
타입 단언 을 이용해 해결하던가 아니면 위의 자바스크립트에서 ?. 연산자를 썼듯이, 물음표를 느낌표로 고대로 바꿔 !. 사용하면 해결할 수 있다.
즉, menu-item 엘리먼트 불러온 동작이 null이나 undefined가 아님은 단언할 수 있을때 비로소 innerHTML에 접근하라는 의미인 것이다.
// Error - TS2531: Object is possibly 'null'.
document.querySelector('.menu-item').innerHTML;
// 타입 단언 (Type assertion)
(document.querySelector('.menu-item') as HTMLDivElement).innerHTML;
(<HTMLDivElement>document.querySelector('.menu-item')).innerHTML;
// Non-null assertion operator
document.querySelector('.menu-item')!.innerHTML;
인터페이스로 다른 예시를 들면 다음과 같다.
interface nameObject {
firstName: string;
lastName: string | null;
}
let obj: nameObject = {
firstName: "Kang",
lastName: null
};
// lastName 키의 값이 string이나 null이 들어올수 있지만 만일 위와 같이 null이 들어와 버리면 toString을 실행할수 없기에
// tsc 컴파일러가 미리 경고를 띄워준다 !!
console.log(obj.lastName.toString());
괜히 타입 가드나 조건에 조건문을 씌우지말고 간단하게 !. 연산자(Non null)을 추가해 해결이 가능하다.
console.log(obj.lastName!.toString());
non-null 단언 연산자를 보다 이해를 돕기 위해 위처럼 설명했지만, 사실 타입스크립트도 자바스크립트의 문법을 모두 포함하기 때문에 옵셔널 체이닝 (?.)을 사용가능하다.
다만, 옵셔널 체이닝 (?.) 과 단언 연산자 (!) 는 서로 뜻하는 바가 다르니 유의하자.
Definite Assignment Assertions
확정 할당 단언(Definite Assignment Assertions)은 생소한 용어일수도 있을텐데, 간단히 말하면 변수에 값이 무조건 할당되어있다고 컴파일러에게 전달하여 값이 없어도 변수 또는 객체를 사용할 수 있다고 단언하는 것이다.
다음과 같이, menu 변수에 실제로 엘리먼트가 있을지 없을지 단언 할 수 없기 때문에 뒤의 menu.innerHTML 코드는 에러가 나게 된다.
const menu = document.querySelector('.menu-item');
menu.innerHTML; // Error
이럴때는 국룰적으로 조건문을 이용해 필터링 하거나, 아니면 확장 할당 단언(!) 을 통해 구현이 가능하다.
const menu = document.querySelector('.menu-item');
if(menu) {
menu.innerHTML;
}
const menu = document.querySelector('.menu-item')!; // 변수 우측에 느낌표를 붙인다.
menu.innerHTML; // Error
이러한 표시는 컴파일러에게 "변수 n는 값이 무조건 값이 할당되어 있다는 것에 내 손모가지를 건다."라고 단언한 것이다.
컴파일러는 아귀가 아닌 쫄보이기 때문에 "네 너님 말에 따르겠습니다. 대신 에러는 너님이 다 책임지세요." 라고 하며 에러 표시줄을 없애 주는 것이다.
즉, 확정 할당 단언은 변수의 값이 무조건 존재한다는 확신이 있을 경우 사용하면 된다.
하지만 가독성을 위해 최대한 느낌표 대신 if문으로 처리하는 걸 추천한다
# 참고자료
https://heropy.blog/2020/01/27/typescript/
이재승 타입스크립트 시작하기
제로초 타입스크립트 올인원
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.