회사에서 생긴 경험을 공유하고자 글을 작성합니다.
마땅한 예제 코드가 없어서... 예시는 가볍게 봐주세요!
function sizeToState(data: {size: number} | undefined | null): 'big' | 'small' | '?' {
if (data === null || data === undefined) {
return '?';
}
if (data.size > 60) {
return 'big';
}
return 'small';
}
size를 크다 작다 혹은 ? 3개중 하나를 반환하는 함수입니다.
if (data === null || data === undefined)
if문을 이렇게 작성하고 return하게 될경우
밑에 data들은 이렇게 타입이 추론되는것을 보실 수 있습니다.
(이것을 타입가드라고 합니다)
하지만,
if ([undefined, null].includes(data)) {
return '?';
}
이렇게 고쳐쓰면 타입가드는 작성하지않습니다.
=== null || === undefined로 쓰나 includes로 쓰나 똑같은데말이죠.
심지어, 저렇게 includes로 사용하면,
TS2345: Argument of type '{ size: number; } | null | undefined' is not assignable to parameter of type 'null | undefined'.
이런 에러까지 뜨고 그럽니다.
그렇습니다. Typescript가 타입체크를 해주는것은 한계가 있습니다.
그래서 저는 이런 한계를 만나는 경우,
//@ts-ignore
if ([undefined, null].includes(data)) {
return '?';
}
이렇게 무시를 하곤 했습니다.
그리고,
if (data.size > 60) {
return 'big';
}
위에서 타입가드가 작동하지않았으므로, 밑에서도 당연히 타입에러가 발생합니다.
아직 data는 undefined일지도 null일지도 모르는데
size라는 프로퍼티로 접근하는 코드가 저렇게 있으니까요.
그래서 이마저도
//@ts-ignore
if ([undefined, null].includes(data)) {
return '?';
}
//@ts-ignore
if (data.size > 60) {
return 'big';
}
이렇게 둘 다 ignore를 해버리게되었습니다.
이런경우, 어떤문제가 발생할까요? 저는 발생하지않을거라 생각했습니다.
null, undefined인 경우에는 무조건 if문을 통해 걸러질거기 때문에,
반드시 size프로퍼티로 접근할 수 있을거라 착각했습니다.
만약, 저 데이터가 서버에서 오는 데이터라고 했을 때,
const data = {
product_size: 123,
productSize: 456
};
위 혹은 아래처럼 size가 아니라 다른 키로 데이터를 서버에서 응답하는경우 어떻게될까요?
분명, 프론트앤드 개발자에게 미리 알려줬을겁니다. size에서 productSize로 바뀔거라구요.
네 맞습니다 저도 그걸 전달받고나서,
interface DataType {
size: number;
}
function sizeToState(data: DataType | undefined | null): '...'
이렇게 되어있던 타입을,
interface DataType {
productSize: number;
}
이렇게 바꿨거든요.
그래서 저 데이터 타입을 사용하는 다른 모든 코드는 전부
size에서 productSize라는 property로 바꾸라는 타입스크립트의 경고를 듣고 수정까지 잘 해줬습니다.
그리고 그거로 끝난줄알았습니다만..........
//@ts-ignore
if (data.size > 60) {
return 'big';
}
여기는 ignore를 했기 때문에 타입을 size에서 productSize로 바뀌는일이 발생한다하더라도
typescript는 저에게 경고를 알려주지 않았습니다.
그리고 프로덕션레벨에서 저거때문에 버그가 발생했습니다.
#세줄요약
1. 경고를 끄면
2. 나중에 타입이 바뀌어도
3. 다시 알려주지 않는다.
다시 돌이켜보자면요,
//@ts-ignore
if (data.size > 60) {
return 'big';
}
처음에 제가 여기서 ignore를 한것은,
"타입가드가 위에서 작동하지않으니까 경고를 무시하려고" 했습니다.
하지만 코드라는건 앞으로 얼마든지 변경할 수 있는 여지가 있기 때문에,
앞으로 영원히 다른 경고 조차도 받을 수 없게된다는 정말 큰 단점을 이번에 알게되었습니다.
분명 제가 의도한건 다른경고도 무시하려고 했던게 아니었거든요.
딱 타입가드 하나만 무시하려고했거든요.
하지만 이렇게됬습니다.
제 실수가 다른분들에게 도움되었으면 좋겠습니다.