|
로 각 타입을 구분//case 1
function (parameter: string | number | boolean) {
// 값의 타입이 number, string, boolean이 될 수 있음을 의미한다.
}
A|B
타입을 가지는 경우 확신할 수 있는 것은 A와 B 둘의 공통 멤버를 가지고 있다는 것 뿐이다. 아래 사례처럼 Fish 타입에만 존재하는 swim 메소드를 이용할 경우 실제 입력된 변수가 Bird인 경우 런타임에서 오류가 발생할 수 있으므로 공통 멤버를 사용해야 한다.
//case 2
interface Bird {
fly(): void;
layEggs(): void;
}
interface Fish {
swim(): void;
layEggs(): void;
}
declare function getSmallPet(): Fish | Bird;
let pet = getSmallPet();
pet.layEggs(); // 두 타입에 공통으로 존재
pet.swim(); // 두 타입 중 하나에서만 사용 가능
유니언을 사용할 때 TypeScript가 현재 가능한 타입 추론의 범위를 좁혀나가게 해줄 수 있는 리터럴 타입을 갖는 단일 필드를 사용하는 것이 일반적이다.
공통 필드인 state가 아닌 다른 프로퍼티에 접근하는 것은 오류를 발생시키기 때문이다.
아래 사례에서 state가 그 역할을 한다. switch문을 이용해 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}`;
}
}
&
로 각 타입을 결합
interface ErrorHandling {
success: boolean;
error?: { message: string };
}
interface ArtworksData {
artworks: { title: string }[];
}
interface ArtistsData {
artists: { name: string }[];
}
// 이 인터페이스들은
// 하나의 에러 핸들링과 자체 데이터로 구성된다.
type ArtworksResponse = ArtworksData & ErrorHandling;
type ArtistsResponse = ArtistsData & ErrorHandling;