ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [TypeScript] 유니언과 교차타입
    TypeScript 2022. 9. 10. 17:15
    728x90

    유니언 타입(Union Types)

    유니언 타입은 여러 타입 중 하나가 될 수 있는 값을 의미합니다. 세로 막대(|) 로 각 타입을 구분합니다. number | string | boolean 은 타입이 number 또는 string 또는 boolean 이 될 수 있음을 뜻합니다.

    공통 필드를 갖는 유니언(Unions with common Fields)

     // @errors: 2339
    
    interface Bird {
      fly(): void;
      layEggs(): void;
    }
    
    interface Fish {
      swim(): void;
      layEggs(): void;
    }
    
    declare function getSmallPet(): Fish | Bird;
    
    let pet = getSmallPet();
    pet.layEggs();
    
    // 두 개의 잠재적인 타입 중 하나에서만 사용할 수 있습니다.
    pet.swim();
    

    여기서 pet은 Fish | Bird 라는 유니온 타입을 갖고 있습니다. TypeScript는 Fish 와 Bird 모두 갖고 있는 멤버에만 접근이 가능합니다.(즉 우리가 흔히 | 는 합집합으로 생각할 수 있지만 TypeScript에서는 교집합임을 유의해야합니다.) 따라서 pet.layEggs()는 괜찮지만 pet.swim()은 에러가 발생합니다.

    유니언 구별하기(Discriminating Unions)

    type NetworkLoadingState = {
      state: "loading";
    };
    
    type NetworkFailedState = {
      state: "failed";
      code: number;
    };
    
    type NetworkSuccessState = {
      state: "success";
      response: {
        title: string;
        duration: number;
        summary: string;
      };
    };
    
    // 위 타입들 중 단 하나를 대표하는 타입을 만들었지만,
    // 그것이 무엇에 해당하는지 아직 확실하지 않습니다.
    type NetworkState =
      | NetworkLoadingState
      | NetworkFailedState
      | NetworkSuccessState;
    

    위와 같은 타입이 있다고 생각했을 때 위 세 타입들은 모두 state라는 필드를 갖고 있으며, 그들 각자만의 필드도 갖고 있습니다.

    NetworkLoadingState NetworkFailedState NetworkSuccessState

    state state state
      code response

    그럼 TypeScript는 state의 존재 여부를 체크하지 않고도 접근할 수 있습니다. 그럼 TypeScript는 state를 통해 현재 어떤 타입인지 알 수 있습니다.

    type NetworkLoadingState = {
      state: "loading";
    };
    
    type NetworkFailedState = {
      state: "failed";
      code: number;
    };
    
    type NetworkSuccessState = {
      state: "success";
      response: {
        title: string;
        duration: number;
        summary: string;
      };
    };
    // ---생략---
    type NetworkState =
      | NetworkLoadingState
      | NetworkFailedState
      | NetworkSuccessState;
    
    function networkStatus(state: NetworkState): string {
      // 현재 TypeScript는 셋 중 어떤 것이
      // state가 될 수 있는 잠재적인 타입인지 알 수 없습니다.
    
      // 모든 타입에 공유되지 않는 프로퍼티에 접근하려는 시도는
      // 오류를 발생시킵니다.
      state.code;
    
      // state에 swtich문을 사용하여, TypeScript는 코드 흐름을 분석하면서
      // 유니언 타입을 좁혀나갈 수 있습니다.
      switch (state.state) {
        case "loading":
          return "Downloading...";
        case "failed":
          // 여기서 타입은 NetworkFailedState일 것이며,
          // 따라서 `code` 필드에 접근할 수 있습니다.
          return `Error ${state.code} downloading`;
        case "success":
          return `Downloaded ${state.response.title} - ${state.response.summary}`;
      }
    }
    

    이 예제를 통해 switch case문의 case ‘success’에서 TypeScript는 아 NetworkSuccessState구나! 를 알기 때문에 state.response 호출이 가능해집니다.

    교차 타입(Intersection Types)

    교차 타입은 유니언 타입과 밀접한 관련이 있지만, 사용 방법은 매우 다릅니다.

    예를들어 Person & Serializable 은 Person 과 Serializable 입니다. 이 타입의 객체는 두 가지 타입의 모든 멤버를 갖게 됩니다.

    교차를 통한 믹스인(Mixins via Intersections)

    class Person {
      constructor(public name: string) {}
    }
    
    interface Loggable {
      log(name: string): void;
    }
    
    class ConsoleLogger implements Loggable {
      log(name: string) {
        console.log(`Hello, I'm ${name}.`);
      }
    }
    
    // 두 객체를 받아 하나로 합칩니다.
    function extend<First extends {}, Second extends {}>(
      first: First,
      second: Second
    ): First & Second {
      const result: Partial<First & Second> = {};
      for (const prop in first) {
        if (first.hasOwnProperty(prop)) {
          (result as First)[prop] = first[prop];
        }
      }
      for (const prop in second) {
        if (second.hasOwnProperty(prop)) {
          (result as Second)[prop] = second[prop];
        }
      }
      return result as First & Second;
    }
    
    const jim = extend(new Person("Jim"), ConsoleLogger.prototype);
    jim.log(jim.name);
    
    • 믹스인 패턴 : 프로토타입을 바꾸지 않고 한 객체의 프로퍼티를 다른 객체에 “복사"하여 사용하는 방식

     

    참고

    https://typescript-kr.github.io/docs/handbook/mixins.html

    728x90

    'TypeScript' 카테고리의 다른 글

    [TypeScript] 제네릭  (0) 2022.09.17
    [TypeScript] 열거형  (1) 2022.09.16
    [TypeScript] 클래스  (0) 2022.09.15
    [TypeScript] 인터페이스  (0) 2022.09.08
    [TypeScript] 기본 타입  (2) 2022.09.07

    댓글

Designed by Tistory.