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)
  • 블로그 메뉴

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

  • 공지사항

  • 인기 글

  • 태그

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

  • 최근 글

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

티스토리툴바