title | layout | permalink | oneline |
---|---|---|---|
Unions and Intersection Types |
docs |
/docs/handbook/unions-and-intersections.html |
How to use unions and intersection types in TypeScript |
์ง๊ธ๊น์ง, ํธ๋๋ถ์ ์์ ๊ฐ์ฒด์ ํ์ ๋ค์ ๋ค๋ค์์ต๋๋ค. ํ์ง๋ง, ๋ ๋ง์ ํ์ ์ ๋ชจ๋ธ๋งํ ์๋ก ์ฒ์๋ถํฐ ํ์ ์ ๋ง๋ค์ด๋ด๊ธฐ๋ณด๋ค๋ ์ด๋ฏธ ์กด์ฌํ๋ ํ์ ์ ๊ตฌ์ฑํ๊ฑฐ๋ ๊ฒฐํฉํ๋ ๋ฐฉ๋ฒ๋ค์ ์ฐพ๊ฒ ๋ ๊ฒ์ ๋๋ค.
๊ต์ฐจ ํ์ ๊ณผ ์ ๋์ธ ํ์ ์ ํ์ ์ ๊ตฌ์ฑํ ์ ์๋ ๋ฐฉ๋ฒ ์ค ํ๋์ ๋๋ค.
๊ฐ๋, number
๋ string
์ ๋งค๊ฐ๋ณ์๋ก ๊ธฐ๋ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ ๋๊ฐ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, ๋ค์ ํจ์๋ฅผ ์ฌ์ฉํ ๋์
๋๋ค:
/**
* ๋ฌธ์์ด์ ๋ฐ๊ณ ์ผ์ชฝ์ "padding"์ ์ถ๊ฐํฉ๋๋ค.
* ๋ง์ฝ 'padding'์ด ๋ฌธ์์ด์ด๋ผ๋ฉด, 'padding'์ ์ผ์ชฝ์ ๋ํด์ง ๊ฒ์
๋๋ค.
* ๋ง์ฝ 'padding'์ด ์ซ์๋ผ๋ฉด, ๊ทธ ์ซ์๋งํผ์ ๊ณต๋ฐฑ์ด ์ผ์ชฝ์ ๋ํด์ง ๊ฒ์
๋๋ค.
*/
function padLeft(value: string, padding: any) {
if (typeof padding === "number") {
return Array(padding + 1).join(" ") + value;
}
if (typeof padding === "string") {
return padding + value;
}
throw new Error(`Expected string or number, got '${padding}'.`);
}
padLeft("Hello world", 4); // "Hello world"๋ฅผ ๋ฐํํฉ๋๋ค.
์ ์์ ์์ padLeft
์ ๋ฌธ์ ๋ ๋งค๊ฐ๋ณ์ padding
์ด any
ํ์
์ผ๋ก ๋์ด์๋ค๋ ๊ฒ์
๋๋ค.
์ฆ, number
๋ string
๋ ๋ค ์๋ ์ธ์๋ก ํจ์๋ฅผ ํธ์ถํ ์ ์๋ค๋ ๊ฒ์ด๊ณ , TypeScript๋ ์ด๋ฅผ ๊ด์ฐฎ๋ค๊ณ ๋ฐ์๋ค์ผ ๊ฒ์
๋๋ค.
declare function padLeft(value: string, padding: any): string;
// ---์๋ต---
// ์ปดํ์ผ ํ์์๋ ํต๊ณผํ์ง๋ง, ๋ฐํ์์๋ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
let indentedString = padLeft("Hello world", true);
์ ํต์ ์ธ ๊ฐ์ฒด์งํฅ ์ฝ๋์์, ํ์
์ ๊ณ์ธต์ ์์ฑํ์ฌ ๋ ํ์
์ ์ถ์ํํ ์ ์์ต๋๋ค.
์ด๋ ๋ ๋ช
์์ ์ผ ์๋ ์์ง๋ง, ์กฐ๊ธ ๊ณผํ๋ค๊ณ ํ ์๋ ์์ต๋๋ค.
๊ธฐ์กด ๋ฐฉ๋ฒ์ padLeft
์์ ์ข์ ์ ์ค ํ๋๋ ์์ ๊ฐ์ ๋จ์ง ์ ๋ฌํ ์ ์๋ค๋ ๊ฒ์
๋๋ค.
์ฆ ์ฌ์ฉ๋ฒ์ด ๊ฐ๋จํ๊ณ ๊ฐ๊ฒฐํฉ๋๋ค.
๋ํ ์ด ์๋ก์ด ๋ฐฉ๋ฒ์ ๋จ์ง ๋ค๋ฅธ ๊ณณ์ ์ด๋ฏธ ์กด์ฌํ๋ ํจ์๋ฅผ ์ฌ์ฉํ๊ณ ์ ํ ๋ ๋์์ด ๋์ง ์์ต๋๋ค.
any
๋์ ์, _์ ๋์ธ ํ์
_์ ๋งค๊ฐ๋ณ์ padding
์ ์ฌ์ฉํ ์ ์์ต๋๋ค:
// @errors: 2345
/**
* ๋ฌธ์์ด์ ๋ฐ๊ณ ์ผ์ชฝ์ "padding"์ ์ถ๊ฐํฉ๋๋ค.
* ๋ง์ฝ 'padding'์ด ๋ฌธ์์ด์ด๋ผ๋ฉด, 'padding'์ ์ผ์ชฝ์ ๋ํด์ง ๊ฒ์
๋๋ค.
* ๋ง์ฝ 'padding'์ด ์ซ์๋ผ๋ฉด, ๊ทธ ์ซ์๋งํผ์ ๊ณต๋ฐฑ์ด ์ผ์ชฝ์ ๋ํด์ง ๊ฒ์
๋๋ค.
*/
function padLeft(value: string, padding: string | number) {
// ...
}
let indentedString = padLeft("Hello world", true);
์ ๋์ธ ํ์
์ ์ฌ๋ฌ ํ์
์ค ํ๋๊ฐ ๋ ์ ์๋ ๊ฐ์ ์๋ฏธํฉ๋๋ค.
์ธ๋ก ๋ง๋ (|
)๋ก ๊ฐ ํ์
์ ๊ตฌ๋ถํ์ฌ, number | string | boolean
์ ๊ฐ์ ํ์
์ด number
, string
ํน์ boolean
์ด ๋ ์ ์์์ ์๋ฏธํฉ๋๋ค.
์ ๋์ธ ํ์ ์ธ ๊ฐ์ด ์์ผ๋ฉด, ์ ๋์ธ์ ์๋ ๋ชจ๋ ํ์ ์ ๊ณตํต์ธ ๋ฉค๋ฒ๋ค์๋ง ์ ๊ทผํ ์ ์์ต๋๋ค.
// @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();
์ฌ๊ธฐ์ ์ ๋์ธ ํ์
์ ์ฝ๊ฐ ๊น๋ค๋ก์ธ ์ ์์ผ๋, ์ต์ํด์ง๋ ๋ฐ ์ฝ๊ฐ์ ์ง๊ด๋ง ์์ผ๋ฉด ๋ฉ๋๋ค.
๋ง์ฝ ๊ฐ์ด A | B
ํ์
์ ๊ฐ๊ณ ์์ผ๋ฉด, ํ์ ํ ์ ์๋ ๊ฒ์ ๊ทธ ๊ฐ์ด A
์B
๋ ๋ค ๊ฐ์ง๊ณ ์๋ ๋ฉค๋ฒ๋ค์ ๊ฐ๊ณ ์๋ค๋ ๊ฒ๋ฟ์
๋๋ค.
์ด ์์ ์์, Bird
๋ fly
๋ผ๋ ๋ฉค๋ฒ๋ฅผ ๊ฐ๊ณ ์์ต๋๋ค.
Bird | Fish
๋ก ํ์
์ด ์ง์ ๋ ๋ณ์๊ฐ fly
๋ฉ์๋๋ฅผ ๊ฐ์ง๊ณ ์๋์ง ํ์ ํ ์ ์์ต๋๋ค.
๋ง์ฝ ๋ณ์๊ฐ ์ค์ ๋ก ๋ฐํ์์ Fish
์ด๋ฉด, pet.fly()
๋ฅผ ํธ์ถํ๋ ๊ฒ์ ์ค๋ฅ์
๋๋ค.
์ ๋์ธ์ ์ฌ์ฉํ๋ ๋ฐ ์์ด์ ์ผ๋ฐ์ ์ธ ๊ธฐ์ ์ TypeScript๊ฐ ํ์ฌ ๊ฐ๋ฅํ ํ์ ์ถ๋ก ์ ๋ฒ์๋ฅผ ์ขํ๋๊ฐ๊ฒ ํด์ค ์ ์๋ ๋ฆฌํฐ๋ด ํ์ ์ ๊ฐ๋ ๋จ์ผ ํ๋๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ๋๋ค. ์๋ฅผ ๋ค์ด, ํ๋์ ๊ณตํต ํ๋๋ฅผ ๊ฐ์ง๊ณ ์๋ ์ธ ๊ฐ์ง ํ์ ์ ์ ๋์ธ์ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค.
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 |
state
ํ๋๊ฐ NetworkState
์์ ๋ชจ๋ ํ์
์ ๊ณตํต์ผ๋ก ์กด์ฌํ๋ค๋ ์ ์ ์๋ค๋ฉด - ์กด์ฌ ์ฌ๋ถ๋ฅผ ์ฒดํฌํ์ง ์๊ณ ๋ ์ ๊ทผํ ์ ์์ต๋๋ค.
๋ฆฌํฐ๋ด ํ์
์ผ๋ก์ state
๋ฅผ ๊ฐ๊ณ ์๋ค๋ฉด, state
์ ๊ฐ์ ๋์ํ๋ ๋์ผํ ๋ฌธ์์ด๊ณผ ๋์กฐ๋๊ณ TypeScript๋ ํ์ฌ ์ด๋ค ํ์
์ด ์ฌ์ฉ๋๊ณ ์๋์ง ์ ๊ฒ์
๋๋ค.
NetworkLoadingState |
NetworkFailedState |
NetworkSuccessState |
---|---|---|
"loading" |
"failed" |
"success" |
์ด ๊ฒฝ์ฐ, ๋ฐํ์์ ๋ํ๋๋ ํ์
์ ๋ฒ์๋ฅผ ์ขํ๊ธฐ ์ํ์ฌ switch
๋ฌธ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
// @errors: 2339
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}`;
}
}
๊ต์ฐจ ํ์
์ ์ ๋์ธ ํ์
๊ณผ ๋ฐ์ ํ ๊ด๋ จ์ด ์์ง๋ง, ์ฌ์ฉ ๋ฐฉ๋ฒ์ ๋งค์ฐ ๋ค๋ฆ
๋๋ค.
๊ต์ฐจ ํ์
์ ์ฌ๋ฌ ํ์
์ ํ๋๋ก ๊ฒฐํฉํฉ๋๋ค.
๊ธฐ์กด ํ์
์ ํฉ์ณ ํ์ํ ๊ธฐ๋ฅ์ ๋ชจ๋ ๊ฐ์ง ๋จ์ผ ํ์
์ ์ป์ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด, Person & Serializable & Loggable
์ Person
๊ณผ Serializable
๊ทธ๋ฆฌ๊ณ Loggable
์
๋๋ค.
์ฆ, ์ด ํ์
์ ๊ฐ์ฒด๋ ์ธ ๊ฐ์ง ํ์
์ ๋ชจ๋ ๋ฉค๋ฒ๋ฅผ ๊ฐ๊ฒ ๋ฉ๋๋ค.
์๋ฅผ ๋ค์ด, ์ผ๊ด๋ ์๋ฌ๋ฅผ ๋ค๋ฃจ๋ ์ฌ๋ฌ ๋คํธ์ํฌ ์์ฒญ์ด ์๋ค๋ฉด ํด๋น ์๋ฌ ํธ๋ค๋ง์ ๋ถ๋ฆฌํ์ฌ ํ๋์ ์๋ต ํ์ ์ ๋์ํ๋ ๊ฒฐํฉ๋ ์์ฒด ํ์ ์ผ๋ก ๋ง๋ค ์ ์์ต๋๋ค.
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;
const handleArtistsResponse = (response: ArtistsResponse) => {
if (response.error) {
console.error(response.error.message);
return;
}
console.log(response.artists);
};
๊ต์ฐจ๋ ๋ฏน์ค์ธ ํจํด์ ์คํํ๊ธฐ ์ํด ์ฌ์ฉ๋ฉ๋๋ค.
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);