개발 공부 일지/TypeScript

[TS] 타입스크립트 !(Non-null assertion operator)

dev-hpk 2024. 11. 19. 18:21

타입스크립트를 사용하다 보면 종종 변수나 객체가 null 또는 undefined일 가능성을 처리해야 하는 상황을 마주하게 됩니다. 이때 non-null assertion (!) 연산자를 활용하면 코드의 가독성을 유지하면서 특정 값이 반드시 null 또는 undefined가 아님을 컴파일러에게 확신시킬 수 있습니다.

 

목차

1. Non-Null Assertion(!)이란?

2. Non-Null Assertion(!) 적용

3. Non-Null Assertion(!) 주의점

4. Non-Null Assertion을 대체할 방법

추천글

위의 목차를 클릭하면 해당 글로 자동 이동 합니다.

 

1. non-null assertion이란?

Non-Null Assertion(!)은 TypeScript에서 사용되는 특별한 연산자로, 컴파일러에게 "이 값은 절대 null이나 undefined가 될 수 없다"는 것을 단언합니다.

value!;

 

위와 같이 변수 뒤에 !를 붙이면 해당 변수가 null 또는 undefined가 아니라는 확신을 나타냅니다.

 

2. Non-Null Assertion 적용

React 프로젝트에 TypeScript를 적용하던 중 아래 코드에서 타입 에러가 발생했습니다.

const root = ReactDOM.createRoot(document.getElementById("root"));

 

document.getElementById의 반환 값이 HTMLElement | null 타입으로 정의되어 있기 때문에 발생합니다. ReactDOM의 createRoot 메서드는 null 값을 허용하지 않으므로 TypeScript에서 타입 검사를 통과하지 못합니다.

 

Non-Null Assertion 적용 예시

const root = ReactDOM.createRoot(document.getElementById("root")!);

!(Non-null assertion operator)를 사용해 TypeScript에게 이 값이 절대 null 또는 undefined가 아님을 보증해 타입 에러가 사라졌습니다. 하지만 이는 런타임 에러를 발생시킬 수 있으므로 보다 안전한 방법을 사용하는 것이 좋습니다.

3. Non-Null Assertion(!) 주의점

3.1. 런타임 에러 가능성

Non-Null Assertion(!)을 사용하면 컴파일러는 더 이상 해당 값의 null 여부를 검사하지 않지만, 런타임에서 null 또는 undefined라면 에러가 발생합니다.

위 코드는 value를 선언만 하고 초기화하지 않아서 undefined일 수 있다는 타입 에러가 발생합니다.

Non-Null Assertion을 적용해 보겠습니다.

타입 에러가 사라진 것을 볼 수 있습니다. 컴파일을 통해 확인해 볼까요?

런타임에서 value가 undefined이기 때문에 에러가 발생합니다. 따라서 Non-Null Assertion(!)은 정말 값이 null이 아니라고 확신할 수 있을 때만 사용해야 합니다.

3.2. 타입 안정성 저하

  • TypeScript의 가장 큰 장점은 코드 작성 중에 타입 안전성을 보장함으로써 잠재적인 버그를 예방하는 것입니다. 그러나 Non-Null Assertion(!)는 타입 검사 과정을 무시하기 때문에 컴파일러가 원래 감지할 수 있는 오류를 놓치게 만듭니다.
  • "이 값이 반드시 존재한다"는 확신을 가지고 Non-Null Assertion(!)를 사용했더라도, 코드가 복잡해지거나 다른 개발자가 추가로 작업하게 되면 Non-Null Assertion(!)로 단언했던 조건이 더 이상 보장되지 않을 수 있습니다.

4. Non-Null Assertion을 대체할 방법

4.1. 옵셔널 체이닝

TypeScript 3.7 이후 도입된 옵셔널 체이닝(?.)null 병합 연산자(??)를 사용하면 보다 안전하고 읽기 쉬운 코드를 작성할 수 있습니다.

function printLength(value?: string) {
  console.log(value?.length ?? 0); // 값이 undefined이면 0 반환
}

4.2. 타입 가드를 사용해 안전성 확보

타입 가드는 값을 명시적으로 검사하므로 런타임 에러를 방지할 수 있습니다.

function getLength(value?: string): number {
  if (value) {
    return value.length;
  }
  throw new Error("value가 undefined | null 입니다.");
}

4.3. 기본값 사용

기본값 설정을 통해 null이나 undefined를 처리합니다.

function getLength(value?: string): number {
  return (value ?? "").length; // value가 null/undefined일 경우 빈 문자열로 대체
}

4.4. 타입 좁히기(Narrowing)

TypeScript의 타입 좁히기를 활용하여 컴파일러가 값이 안전하다고 추론할 수 있게 합니다.

function printUserId(userId?: number) {
  if (userId !== undefined) {
    console.log(userId.toString()); // 타입 좁히기로 안전한 접근
  } else {
    console.log("유저 아이디가 없습니다.");
  }
}

 

 

 

Non-Null Assertion(!)은 편리한 도구지만, 과도하게 사용하면 TypeScript의 타입 시스템을 무력화할 위험이 있습니다. 특정 값이 null이나 undefined가 아님을 확신할 때만 사용해야 하며, 대신 타입 가드, 옵셔널 체이닝, 기본값 설정, 타입 좁히기 등 더 안전한 대안을 적극적으로 고려하는 것이 좋습니다.

 

"컴파일러 경고를 피하는 대신, 문제의 원인을 해결하자"라는 마음가짐으로 같이 공부해 봐요🔥🔥🔥

 

 

 

[TS] any 타입 - 편리함과 위험함 사이

any 타입은 TypeScript에서 가장 강력하면서도 동시에 논란이 많은 타입 중 하나입니다. 편리할 수 있지만, 잘못 사용하면 코드의 안정성과 가독성을 크게 떨어뜨릴 수 있습니다. any 타입의 역할과

dev-hpk.tistory.com

 

 

[TS] 타입 추론과 타입 단언

타입스크립트(TypeScript)는 정적 타입 시스템을 통해 코드의 안전성을 높이고, 버그를 줄이는 데 유용한 언어입니다. 그중에서도 타입 추론과 타입 단언은 TypeScript의 강력한 기능입니다. 목차 1.

dev-hpk.tistory.com