아이템 31. 타입 주변에 Null 값 배치하기

아이템 31. 타입 주변에 Null 값 배치하기

아이템 31. 타입 주변에 null 값 배치하기 #

값이 전부 null, null이 아닌 경우로 분명히 구분한다면 값이 섞여 있을 때보다 다루기 쉽다.

  • if 혹은 !(단언) 을 통해 쉽게 타입을 좁힐 수 있다.

추가로 undefined 를 포함하는 객체는 다루기 어렵고 절대 권장하지 않는다.

타입에 null 을 추가하는 방식으로 이러한 경우를 모델링할 수 있다.

function extent(nums: number[]) {
    let result: [number, number] | null = null;

    for (const num of nums) {
        if(!result) {
            result = [num, num];
        } else {
            result = [Math.min(num, results[0]), Math.min(num, results[1])]
        }
    }

    return result;
}

// 반환 타입(return result)이 [number, number] | null 이 되어서 사용하기가 더 수월해진다.
// (= undefined 를 명시적으로 없애는 것이 중요하다고 말하는 것 같다.)



null, null이 아닌 값을 섞어서 사용하면 안좋다. #

class UserPosts {
    user: UserInfo | null;
    posts: Post[] | null;

    constructor() {
        this.user = null;
        this.posts = null;
    }

    async init(userId: string) {
        return Promise.all([
            async () => this.user = await fetchUser(userId),
            async () => this.posts = await fetchPostsForUser(userId),
        ]);
    }

    getUserName() {
        // ...?
    }
}

두 번의 네트워크 요청(fetchUser, fetchPostsForUser) 동안 user, posts 속성은 null 값이다.

특정 시점에는 아래와 같은 경우의 수를 가질 수 있다. (두 변수에 대해서만 계산해도 4가지이다.)

  • user : null , posts : null
  • user : not null , posts : not null
  • user : null , posts : not null
  • user : not null , posts : null

속성 값의 불확실성(null, not null)이 클래스의, 메서드의 모든 부분에 나쁜 영향을 미친다.
= null 체크가 난무하고, 버그를 양산한다.

아래와 같이 개선해볼 수 있다.

class UserPosts {
    user: UserInfo;
    posts: Post[];

    constructor(user: UserInfo, posts: Post[]) {
        this.user = user;
        this.posts = posts;
    }

    static async init(userId: string): Promise<UserPosts> {
        const [user, posts] = await Promise.all([
            fetchUser(userId),
            fetchPostsForUser(userId)
        ]);

        return new UserPosts(user, posts);
    }

    getUserName() {
        return this.user.name;
    }
}

UserPosts 클래스는 이제 null 인 경우의 수를 고려하지 않아도 된다.
= 이제 클래스, 메서드를 작성하기 쉬워졌다.



요약 & 정리 #

  • 한 값의 null 여부가 다른 값의 null 여부에 암시적으로 관련되도록 설계하며 안된다.
    • 즉, null 값들이 관계가 있어서 위의 예시처럼 n^2 와 같은 경우의 수가 나오지 않도록 한다.
  • API 작성 시 ‘반환 타입’을 (전체가) null 이거나, (전체가) null 이 아니게 만들어야 한다.
  • 클래스를 만들 때는 필요한 모든 값이 준비되었을 때 생성하여 null 이 존재하지 않도록 한다.
  • strictNullChecks 를 설정하자.

아래 내용은 기억하자.

" 클래스를 만들 때는 필요한 모든 값이 준비되었을 때 생성하여 null 이 존재하지 않도록 한다. “