logo
Search검색어를 포함하는 게시물들이 최신순으로 표시됩니다.
    Table of Contents
    [TS] Union 타입과 Intersection 타입

    이미지 보기

    [TS] Union 타입과 Intersection 타입

    • 23.10.04 작성

    • 읽는 데 5

    TOC

    타입은 할당 가능한 값들의 집합

    never

    • 가장 작은 집합은 아무 값도 포함하지 않는 공집합
    • never 타입으로 선언된 변수는 어떤 값도 할당할 수 없다.

    unit (literal type)

    • 한 가지 값만 포함하는 타입
    type A = 'A';
    type B = 'B';
    type Twelve = 12;
    

    Union Type

    • 두 개 혹은 세 개의 타입을 묶는 타입
    • 값 집합들의 합집합
    type AB = 'A' | 'B';
    type AB12 = 'A' | 'B' | 12;
    

    Intersection과 Union

    Intersection

    intersection을 교집합, union을 합집합이라고 생각해보자.

    interface Person {
      name: string;
    }
    
    interface Lifespan {
      birth: Date;
      death?: Date;
    }
    
    type PersonSpan = Person & Lifespan;
    
    • PersonSpan 타입은 Person과 Lifespan의 교집합이다.
    • Person과 Lifespan은 공통으로 가지는 속성이 없기 때문에 공집합(never타입)으로 생각하기 쉽다.
    • 하지만 타입 연산자는 인터페이스의 속성이 아닌, 값의 집합(타입의 범위)에 적용된다. 그리고 추가적인 속성을 가지는 값도 여전히 그 타입에 속하게 된다.
    • 때문에 person과 Lifespan을 둘 다 가지는 값은 Intersection 타입에 속하게 된다.
    const person: PersonSpan = {
      name: 'Alan Turing',
      birth: new Date('1912/06/23'),
      death: new Date('1954/06/07'),
    }; // OK
    
    • 다시 말하면 Intersection 타입은 두 타입의 교집합이므로, 두 타입의 모든 속성을 가져야 한다.

    Union 타입

    type K = keyof (Person | Lifespan); // type이 never
    
    • 두 interface의 속성 중 겹치는 것이 없기 때문에 K 타입은 never 타입이 된다.
    • 이를 수식으로 표현하면 이와 같다.
    keyof (A&B) = keyof A | keyof B
    keyof (A|B) = keyof A & keyof B
    

    보다 세밀한 예시를 살펴보자.

    interface Person {
      name: string;
      age: number;
    }
    interface Developer {
      name: string;
      skill: string;
    }
    function introduce(someone: Person | Developer) {
      someone.name; // O 정상 동작
      someone.age; // X 타입 오류
      someone.skill; // X 타입 오류
    }
    
    • 타입스크립트 관점에서는 introduce() 함수를 호출하는 시점에 Person 타입이 올지 Developer 타입이 올지 알 수가 없기 때문에 어느 타입이 들어오든 간에 오류가 안 나는 방향으로 타입을 추론하게 된다.
    • 때문에 Union 타입이라고 완전히 넓은 범위로 활용할 수 있을 것이라 생각하면 안 된다.
    • 기본적으로는 PersonDeveloper 두 타입에 공통적으로 들어있는 속성인 name만 접근할 수 있게 된다.

    Union Type의 장점

    Union 타입을 사용하였을 때의 장점이 뭘까?

    // any를 사용하는 경우
    function getAge(age: any) {
      age.toFixed(); // 에러 발생
      return age;
    }
    
    • 위의 경우 any 타입을 사용하였기 때문에 age의 타입이 any로 추론된다. 따라서 숫자 관련된 API를 사용할 때 코드가 자동 완성되지 않는다.
    • 이를 Union 타입과 Type Guard를 활용하여 해결할 수 있다.

    // 유니온 타입을 사용하는 경우
    function getAge(age: number | string) {
      if (typeof age === 'number') {
        age.toFixed(); // 정상 동작
        return age;
      }
      if (typeof age === 'string') {
        return age;
      }
      return new TypeError('age must be number or string');
    }
    
    • 함수의 인자는 numberstring으로 유연하게 받을 수 있게 설정하였다.
    • typeof를 통해 numberstring을 구분하고, 각각의 타입에 맞는 API를 사용할 수 있다.
    • age의 타입이 number인 경우 숫자 관련된 API를 쉽게 자동완성 할 수 있다.

    References

    profile

    FE Developer 박승훈

    노력하는 자는 즐기는 자를 이길 수 없다