-
[TypeScript] 유니언과 교차타입TypeScript 2022. 9. 10. 17:15728x90
유니언 타입(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);
- 믹스인 패턴 : 프로토타입을 바꾸지 않고 한 객체의 프로퍼티를 다른 객체에 “복사"하여 사용하는 방식
참고
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