non-null 단언 연산자(!), null 병합 연산자(??) 그리고 옵셔널 체이닝(.?)

2024. 12. 22. 14:29·Backend/TypeScript

! (Non-null assertion operator)

!연산자는 개발자가 "이 값은 확실히 null/undefined가 아니다"라고 TypeScript 컴파일러에게 알려주는 것입니다. 하지만 실제 런타임에서는 아무런 체크도 하지 않기 때문에, 확실히 보장될때만 사용해야 하며, 가능하다면 if 문으로 null 체크를 하거나 옵셔널 체이닝을 사용하는 것이 더 안전한 방법입니다.

 

1. Null 체크 우회

name은 string | null 이지만, 개발자가 이 시점에서 확실히 null이 아님을 알고 있을 때 사용하면 됩니다. 

// 1. NULL 체크 우회
let name: string | null = "Ecount";
let nameLength = name!.length;

 

 

2. 초기화 체크 우회

클래스 필드 name이 생성자에서 직접 초기화되지 않고, 다른 메소드에서 초기화될 것임을 알려줍니다. !가 없으면 TypeScript는 name이 생성자에서 초기화되지 않았다고 경고를 줍니다. 

class User {
    name!: string;
    constructor() {
        this.initalize();
    }
    private initialize() {
        this.name = "ecount";
    }
}

 

 

! 연산자는 타입 체크를 우회하므로 신중하게 사용해야 합니다. 가능하면 타입 가드나 조건문으로 명시적 체크를 하는 것이 더 안전하며, 특히 외부 데이터를 다룰 때는 ! 사용을 피하고 명시적인 null 체크를 하는 것이 더 좋습니다.

// 위험한 방법
function funcA(user: User | null) {
    const name = user!.name;  // 런타임 에러 가능성!
}

// 안전한 방법
function funcB(user: User | null) {
    if (user === null) {
        return;
    }
    const name = user.name;  // 타입 가드 사용
}

 

?. (Optional Chaining)

옵셔널 체이닝은 객체, 배열, 함수에 사용할 수 있습니다. 접근하는 주체의 프로퍼티가 null 또는 undefined일 수 있다면 if 문을 사용하지 않고 넘어가게 하는 방법입니다. 객체가 null 또는 undefined이면 undefined를 리턴하고, 그렇지 않은 경우 데이터 값을 리턴합니다. 보통의 경우 아래와 같은 코드에서 타입 에러가 발생하지만,  && 연산자를 사용하면 문제를 해결할 수 있습니다.

// 1. &&
// 에러가 발생하는 코드
let user = {};

alert(user.address.phone); // TypeError

// 에러가 발생하지 않는 코드
let user = {};

alert(user && user.address && user.address.phone); // undefined


?.의 경우 앞의 대상이 undefined이거나 null일 때 평가를 중단하고 undefined를 반환합니다. 장점은 코드를 간소화할 수 있고, 안전하게 객체에 접근이 가능합니다. 단점은 실제로는 문제가 있는 코드인데 에러가 발생하지 않아 디버깅이 어려울 수 있고, 타입 안정성이 저하됩니다.

let user = {};

alert(user?.address?.street); // undefined

 

 

?? (Nullish Coalescing)

널 병합 연산자는 왼쪽 피연산자가 null이거나 undefined일때만 오른쪽 피연산자를 반환하는 연산자입니다. 아래 코드에 따르면, comparer가 제공되지 않으면 기존에 구현해둔 DefaultGenericComparer를 사용하기 위해 널 병합 연산자를 사용하였습니다.

public constructor(comparer: IEqualityComparer<TValue> | null = null) {
    this._count = 0;
    this._head = null;
    this._tail = null;
    this._comparer = comparer ?? DefaultGenericComparer;
  }




 

'Backend/TypeScript' 카테고리의 다른 글
  • 추상클래스와 제네릭 (실습)
  • 아이템13. type과 interface 차이점 알기
  • Interface (인터페이스)
  • Iteration Protocol (+Symbol)
kimdozzi
kimdozzi
끝까지 포기하지 않으면, 내가 다 이겨!
  • kimdozzi
    도브로
    kimdozzi
  • 전체
    오늘
    어제
    • 분류 전체보기 (132)
      • Problem Solving (49)
        • Baekjoon (29)
        • Programmers (0)
        • LeetCode (17)
        • 삼성 유형 (2)
      • Computer Science (27)
        • Operating System (2)
        • Algorithms (13)
        • Network (6)
        • DataBase (6)
      • Backend (33)
        • JavaScript (0)
        • TypeScript (6)
        • Java (7)
        • Spring Boot (7)
        • Spring Security (6)
        • JPA (2)
        • Mybatis (1)
        • Junit5 (1)
        • Redis (3)
      • DevOps (14)
        • Git, Github (5)
        • docker (4)
        • AWS (3)
        • nginx (2)
      • etc (6)
        • IntelliJ (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
    • 티스토리
    • 설정
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    구간합
    도커
    타입스크립트
    interface
    TypeScript
    오블완
    python
    파이썬
    알고리즘
    S3
    오프라인 쿼리
    컨테이너
    삼성기출
    인덱스 시그니처
    인덱서블 타입
    PrefixSum
    구간 업데이트
    CORS
    티스토리챌린지
    imos법
    누적합
    인터페이스
    segment tree
    docker
    Bucket
    점 업데이트
    백준
    세그먼트 트리
    docker image
    온라인 쿼리
    AWS
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
kimdozzi
non-null 단언 연산자(!), null 병합 연산자(??) 그리고 옵셔널 체이닝(.?)
상단으로

티스토리툴바