개발/language

[TypeScript]타입 할당 ?, !의 차이에 대한 실제 사례 feat.JWT

prpn97 2023. 8. 4. 22:45

계기

이번에 포스팅을 하게 된 계기는 현재 구현하고 있는 프로젝트의 auth 부분에서 다시금 깨닫게 된 것이 있어서인데, 리마인드하는 겸 설명을 붙여보고자 한다. 

 

jwt로 인증을 받게 되면 req.user 로 user에 대한 정보를 받을 수 있다. 그런데 앞서 말했듯 jwt로 인증을 받아야만 req.user를 얻게 되기 때문에 req.user는 확정적으로 값이 있는 변수가 아니다. 인증을 받았을 때만 req.user에 값이 들어오게 된다.

그래서 타입을 세팅하고 선언할 때 req.user에 대해서는 ?를 붙여서 있을 수도 있고~ 없을 수도 있다고 표현했다. 

? 의 의미

위 스샷과 같이 req.user에 username을 얻고 싶을 때 req.user.username으로 받게 되면 자연스럽게 타입스크립트는 나의 의도를 파악하지 못하고 저항한다... 왜냐하면 req.user가 항상 값이 있지는 않으니 조심하라는 것이다. undefined 일 수도 있다고 한다. 내가 그렇게 CustomRequest에 옵셔널하게 세팅했기 때문에 당연한 것이다. 스샷에도 나와있지만 커스텀 리퀘스트에서 user을 ?로 표현했고, 그렇기 때문에 실제로 req.user을 사용하려고 할 때도 없을 수 있다고 표현해주어야 하는 것이다. 

 

그리고 !는 not으로 배웠는데, !가 항상 not으로 쓰이지는 않는다.

변수 뒤에 !를 사용하게 되면 확정 할당 어설션(Definite Assignment Assertions) 용도로 사용할 수 있다.

이름에서 힌트를 얻어보자. 무언가를 확정적으로 할당한다고 한다. 이제 본론으로 들어가보자.

 

!의 의미

결국 ?는 ~일 수도 있고, 아닐 수도 있고~ 라는 애매한 대답을 줄 수 있는 것인데, 이와 반대로 !를 다른 경우에 사용할 수 있다. 앞선 설명과 상반되게 !는 무조건 있다고 확정짓는 것이다. 디폴트로 세팅한 값에는 ~일수도 있고, 아닐 수도 있었지만 지금 선언하는 이 상황에서는 이 값은 무조건 있기 때문에 걱정하지 말라고 알려주는 것이다. 그래서 req.user?을 하면 여전히 애매한 것이고, req.user!로 한다면 이 상황에서는 req.user에는 값이 무조건 있다는 것이다. 

 

 

내가 겪은 상황

나는 로그인하지 않아도 일부 서비스를 사용할 수 있기 때문에 로그인여부를 파악하는 부분에서 로그인이 되어있지 않더라도 next로 넘기려고 구상했다. req.user에 로그인하면 무조건 값이 들어오니까 req.user!.username으로 username을 찾고, username이 없으면 없는 것에 대한 에러처리를 해야겠다고 생각했다. 이에 대한 결과는 다음과 같다. 

username을 찾을 수 없는데, undefined의 프로퍼티를 읽어올 수 없다고 한다. 왜일까?

콘솔로 보통 undefined 인 변수를 확인했을 때 undefined라고 나오는 경우가 허다한데,

왜 디버깅했을 때 undefined라고 예상했던 결과와는 달리 아무것도 반환하지 않을까?

 

이유는 ! 때문이다. 무조건 req.user가 있다고 장담을 했기 때문에 선택지에 undefined 자체가 없는 것이다. 

그래서 req.user가 없는 상태의 조건을 내걸어도 확인할 수가 없다. 왜냐하면 그 전에 undefined라는 선택지를 제거했기 때문에 무조건 true여야 하는데 true가 아닌 그런 이상한 상황이기 때문에 true false조차도 반환하지를 않는다. 

 

미래를 모르기 때문에 이런 상황에

서는 ? 를 사용할 수밖에 없다. 로그인을 할 수도, 안할 수도 있다. 

그럴 때 req.user!를 req.user?.username으로 찾았더니 다른 결과를 불러왔다. 

 

로그인하지 않은 상태에서 api가 호출되면서 아까는 못찾는다고 했던 Username: 에 undefined가 들어왔다. 

(첫줄 '로그인하지 않은 상태' 는 jwt에서 로그인하지 않은 상태에 대해 next로 넘기기 전에 입력해놓은 디버깅 콘솔이다.)

로그인 하지 않았다고 해서 오류는 아니기 때문에 next로 넘겨주었다. 

 

 

코멘트

프로그래밍 언어 또한 언어고, 표현하고자 하는 바가 정확해야 함을 절실히 깨달았다. 하나의 행동을 만들 때 그 행동의 의미를 정확히 알고 있어야 다른 로직과 개연할 수 있고, 이 부분을 간과하면 나중에라도 빈 틈이 생길 수 있음을 깨닫는다. 

728x90