TypeScript와 Next.js로 코드를 작성하다 보니, 종종 낯선 느낌표(!)를 마주쳤다.
내가 아는 느낌표는 != 같은 연산자에 쓰이는 "not" 정도였는데, 갑자기 변수 뒤에 붙는 느낌표가 등장하니 궁금증이 생겼다. 그래서 찾아보았다.
const dislikePost = async () => {
"use server";
try {
const session = await getSession();
await db.like.delete({
where: {
id: {
postId: id,
userId: session.id!,
},
},
});
revalidatePath(/post/${id});
} catch (e) {}
};
session.id!의 느낌표는 TypeScript에서 Non-Null Assertion Operator라고 불린다.
null 또는 undefined가 아닐 것이라고 개발자가 확신하는 경우에 사용한다.null 이나 undefined일 가능성을 엄격하게 체크하기 때문에, 해당값이 확실히 존재한다고 알려주지 않으면 에러를 발생시킬 수 있다.session.id!에 느낌표를 붙였을까?session.id가 타입 정의상 string | undefined와 같이 undefined가 포함될 수 있는 경우, TypeScript는 안전성을 위해 에러를 발생시킬 수 있다.
const session: { id?: string } = { id: undefined }; // id가 없을 수도 있는 상황
이런 상황에서 session.id!는 "내가 개발자인 내가 확신하는데, 이 값은 절대 undefined가 아니야!"라고 TypeScript에게 알려주는 것이다.
즉, !를 붙임으로써 타입 검사기를 속이고 해당 값이 반드시 존재한다고 강제한다.
undefined를 처리하기 위한 의미
undefined와 관련이 있지만 정확히는 TypeScript의 타입 검사기가undefined가능성을 인지하고, 그로 인해 발생할 수 있는 오류를 방지하기 위해 사용하는 것이다.undefined일 수도 있는 값을 개발자가 확실히 존재한다고 보장하기 위한 도구라고 이해하면 쉽다.
!를 사용할 때는 정말 해당 값이 존재한다는 확신이 있을 때만 사용해야 한다. 그렇지 않으면 런타임 오류가 발생할 수 있다.undefined일 가능성을 제대로 처리하고 싶다면 다음과 같이 조건문을 추가하는 것이 더 안전하다.if (!session?.id) {
throw new Error("Session ID is not available!");
}
await db.like.delete({
where: {
id: {
postId: id,
userId: session.id,
},
},
});
유용해 보이지만, 함부로 쓰면 위험할 수 있는 연산자(?)를 또 하나 알게 되었다.
css에서는 !important / typescript any가 있었는데 또 하나 추가되었따.
강제로 선언하는 역할을 하기 때문에 사용하는게 신중함이 필요하다고 했으니 ....
간단한 프로젝트에서는 !의 남발을 피해야겠지만, 프로젝트 규모가 커지면 어쩔 수 없이 사용하는 경우도 생길 것 같다..... 하지만 typescript는 안전성이 중요하기 때문에 안쓰려고 노력해야겠다
실제로 css에서 !important 많이 사용하고 있다 .. 코드가 방대해지면 어쩔 수 없을 거 같다 ^^