# ๐ Item24 ~ 28
# Item24. ์ผ๊ด์ฑ ์๋ ๋ณ์นญ ์ฌ์ฉํ๊ธฐ
- ๋ณ์นญ์ ํ์
์คํฌ๋ฆฝํธ๊ฐ ํ์
์ ์ขํ๋ ๊ฒ์ ๋ฐฉํดํ๋ค.
- ๋ณ์นญ์ ๋จ๋ฐํด์ ์ฌ์ฉํ๋ฉด ์ ์ด ํ๋ฆ์ ๋ถ์ํ๊ธฐ ์ด๋ ต๋ค.
- ๋ฐ๋ผ์ ๋ณ์์ ๋ณ์นญ์ ์ฌ์ฉํ ๋๋ ์ผ๊ด๋๊ฒ ์ฌ์ฉํด์ผ ํ๋ค.
const borough = {
name: 'Brooklyn',
location: [40.688, -73.979],
};
const loc = borough.location;
loc[0] = 0;
console.log(borough.location); // [0, -73.979]
interface Coordinate {
x: number;
y: number;
}
interface BoundingBox {
x: [number, number];
y: [number, number];
}
interface Polygon {
exterior: Coordinate[];
holes: Coordinates[][];
bbox?: BoundingBox;
}
// before
function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
if (polygon.bbox) {
if (pt.x < polygon.bbox.x[0] || pt.x > polygon.bbox.x[1] || pt.y < polygon.bbox.y[0] || pt.y > polygon.bbox.y[1]) {
return false;
}
}
}
// after - ํ์
์ค๋ฅ ๋ฐ์(strictNullChecks ํ์ฑํ ์ํ)
function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
const box = polygon.bbox; // ํ์
์ด BoundingBox | undefined
if (polygon.bbox) {
if (pt.x < box.x[0] || pt.x > box.x[1] || pt.y < box.y[0] || pt.y > box.y[1]) {
return false;
}
}
}
// ์์ ๊ฐ์ ์ํฉ์ด ๋ฐ์ํ ์ด์ ๋ ์์ฑ ์ฒดํฌ๋ polygon.bbox์ ํ์
์ ์ ์ ํ์ง๋ง box๋ ๊ทธ๋ ์ง ์์๊ธฐ ๋๋ฌธ์ด๋ค.
// ์ด๋ฌํ ์ค๋ฅ๋ "๋ณ์นญ์ ์ผ๊ด์ฑ ์๊ฒ ์ฌ์ฉํ๋ค"๋ ๊ธฐ๋ณธ ์์น์ ์งํค๋ฉด ๋ฐฉ์งํ ์ ์๋ค.
function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
const box = polygon.bbox; // ํ์
์ด BoundingBox | undefined
if (box) {
if (pt.x < box.x[0] || pt.x > box.x[1] || pt.y < box.y[0] || pt.y > box.y[1]) {
return false;
}
}
}
- ์์ ๊ฐ์ ์ฝ๋๋ ๊ฐ์ฒด ๋น๊ตฌ์กฐํ๋ฅผ ์ด์ฉํ๋ฉด ๋ณด๋ค ๊ฐ๊ฒฐํ ๋ฌธ๋ฒ์ผ๋ก ์ผ๊ด๋ ์ด๋ฆ์ ์ฌ์ฉํ ์ ์๋ค.
function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
const { bbox } = polygon;
if (bbox) {
const {x, y} = bbox;
if (pt.x < x[0] || pt.x > x[1] || pt.y < y[0] || pt.y > y[1]) {
return false;
}
}
}
- ๊ฐ์ฒด ๋น๊ตฌ์กฐํ ์ด์ฉ์ ์ฃผ์์ฌํญ
- ์ ์ฒด
bbox
์์ฑ์ด ์๋๋ผx
,y
๊ฐ ์ ํ์ ์์ฑ์ผ ๊ฒฝ์ฐ ์์ฑ ์ฒดํฌ๊ฐ ๋ ํ์ํ๋ค.- ๋ฐ๋ผ์ ํ์
์ ๊ฒฝ๊ณ์
null
๊ฐ์ ์ถ๊ฐํ๋ ๊ฒ์ด ์ข๋ค.
- ๋ฐ๋ผ์ ํ์
์ ๊ฒฝ๊ณ์
bbox
์๋ ์ ํ์ ์์ฑ์ด ์ ํฉํ์ง๋งholes
๋ ๊ทธ๋ ์ง ์๋ค.holes
๊ฐ ์ ํ์ ์ด๋ผ๋ฉด, ๊ฐ์ด ์๊ฑฐ๋ ๋น ๋ฐฐ์ด์ด์์ ๊ฒ์ด๋ค.- ์ฐจ์ด๊ฐ ์๋๋ฐ ์ด๋ฆ์ ๊ตฌ๋ณํ ๊ฒ์ด๋ค.
- ๋น ๋ฐฐ์ด์ 'holes ์์'์ ๋ํ๋ด๋ ์ข์ ๋ฐฉ๋ฒ์ด๋ค.
- ์ ์ฒด
- ๋ณ์นญ์ ํ์ ์ฒด์ปค๋ฟ๋ง ์๋๋ผ ๋ฐํ์์๋ ํผ๋์ ์ผ๊ธฐํ ์ ์๋ค.
const { bbox } = polygon;
if (!bbox) {
calculatePolygonBbox(polygon); // polygon.bbox๊ฐ ์ฑ์์ง๋ค.
// ์ด์ polygon.bbox์ bbox๋ ๋ค๋ฅธ ๊ฐ์ ์ฐธ์กฐํ๋ค.
}
- ํ์ ์คํฌ๋ฆฝํธ์ ์ ์ด ํ๋ฆ ๋ถ์์ ์ง์ญ ๋ณ์์๋ ๊ฝค ์ ๋์ํ๋ค. ๊ทธ๋ฌ๋ ๊ฐ์ฒด ์์ฑ์์๋ ์ฃผ์ํด์ผ ํ๋ค.
function fn(p: Polygon) { /* ... */ }
polygon.bbox // ํ์
์ด BoundingBox | undefined
if (polygon.bbox) {
polygon.bbox // ํ์
์ด BoundingBox
fn(polygon);
polygon.bbox // ํ์
์ด BoundingBox
}
fn(polygon);
ํธ์ถ์polygon.bbox
๋ฅผ ์ ๊ฑฐํ ๊ฐ๋ฅ์ฑ์ด ์์ผ๋ฏ๋ก ํ์ ์BoundingBox | undefined
๋ก ๋๋๋ฆฌ๋ ๊ฒ์ด ์์ ํ ๊ฒ์ด๋ค.- ๊ทธ๋ฌ๋ ํจ์๋ฅผ ํธ์ถํ ๋๋ง๋ค ์์ฑ ์ฒดํฌ๋ฅผ ๋ฐ๋ณตํด์ผ ํ๊ธฐ ๋๋ฌธ์ ์ข์ง์๋ค.
- ํจ์ ํธ์ถ์ด ๊ฐ์ฒด ์์ฑ์ ํ์ ์ ์ ๋ฅผ ๋ฌดํจํํ ์ ์๋ค๋ ์ ์ ์ฃผ์ํด์ผ ํ๋ค. ์์ฑ๋ณด๋ค ์ง์ญ ๋ณ์๋ฅผ ์ฌ์ฉํ๋ฉด ํ์ ์ ์ ๋ฅผ ๋ฏฟ์ ์ ์๋ค.
polygon.bbox
๋ก ์ฌ์ฉํ๋ ๋์bbox
์ง์ญ ๋ณ์๋ก ๋ฝ์๋ด์ ์ฌ์ฉํ๋ฉดbbox
ํ์ ์ ์ ํํ ์ ์ง๋๋ง,polygon.bbox
์ ๊ฐ๊ณผ ๊ฐ๊ฒ ์ ์ง๋์ง ์์ ์ ์๋ค.
# Item25. ๋น๋๊ธฐ ์ฝ๋์๋ ์ฝ๋ฐฑ ๋์ async
ํจ์ ์ฌ์ฉํ๊ธฐ
- ์ฝ๋ฐฑ๋ณด๋ค๋ ํ๋ก๋ฏธ์ค๋
async/await
๋ฅผ ์ฌ์ฉํด์ผ ํ๋ ์ด์- ์ฝ๋ฐฑ๋ณด๋ค๋ ํ๋ก๋ฏธ์ค๊ฐ ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ฝ๋ค.
- ์ฝ๋ฐฑ๋ณด๋ค๋ ํ๋ก๋ฏธ์ค๊ฐ ํ์ ์ ์ถ๋ก ํ๊ธฐ ์ฝ๋ค.
- ์์1) ๋ณ๋ ฌ๋ก ํ์ด์ง ๋ก๋
async function fetchPages() {
const [response1, response2, response3] = await Promise.all([
fetch(url1), fetch(url2), fetch(url3)
]);
}
- ์์2)
Promise.race
๋ก ํ์์์ ์ถ๊ฐํ๋ ๋ฐฉ๋ฒPromise.race
์ ๋ฐํ ํ์ ์ ์ ๋ ฅ ํ์ ๋ค์ ์ ๋์จ์ด๊ณ , ์ด๋ฒ ๊ฒฝ์ฐ๋Promise<Response | never>
๊ฐ ๋๋never
์์ ์ ๋์จ์ ์๋ฌด๋ฐ ํจ๊ณผ๊ฐ ์์ผ๋ฏ๋กPromise<Response>
๋ก ๊ฐ๋จํด์ง๋ค.
function timeout(millis: number): Promise<never> {
return new Promise((resolve, reject) => {
setTimeout(() => reject('timeout'), millis);
});
}
async function fetchWithTimeout(url: string, ms: number) {
return Promise.race([fetch(url), timeout(ms)]);
}
- ๊ฐ๋ ํ๋ก๋ฏธ์ค๋ฅผ ์ง์ ์์ฑํด์ผํ ๋ ์ฝ๋ฐฑ API๋ฅผ ๋ํํ ๊ฒฝ์ฐ๊ฐ ์๋๋ฐ ์ ํ์ ์ฌ์ง๊ฐ ์๋ค๋ฉด ์ผ๋ฐ์ ์ผ๋ก๋ ํ๋ก๋ฏธ์ค๋ฅผ ์์ฑํ๊ธฐ ๋ณด๋ค๋
async/await
๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.- ์ผ๋ฐ์ ์ผ๋ก ๋ ๊ฐ๊ฒฐํ๊ณ ์ง๊ด์ ์ธ ์ฝ๋๊ฐ ๋๋ค.
async
ํจ์๋ ํญ์ ํ๋ก๋ฏธ์ค๋ฅผ ๋ฐํํ๋๋ก ๊ฐ์ ๋๋ค.
// function getNumber(): Promise<number>
async function getNumber() {
return 42;
}
const getNumber = async () => 42; // ํ์
์ด () => Promise<number>
const getNumber = () => Promise.resolve(42); // ํ์
์ด () => Promise<number>
async
ํจ์์์ ํ๋ก๋ฏธ์ค๋ฅผ ๋ฐํํ๋ฉด ๋ ๋ค๋ฅธ ํ๋ก๋ฏธ์ค๋ก ๋ํ๋์ง ์๋๋ค.- ๋ฐํ ํ์
์
Promise<Promise<T>>
๊ฐ ์๋Promise<T>
๊ฐ ๋๋ค. - ํ์ ์คํฌ๋ฆฝํธ๋ฅผ ์ฌ์ฉํ๋ฉด ํ์ ์ ๋ณด๊ฐ ๋ช ํํ ๋๋ฌ๋๋ฏ๋ก ๋น๋๊ธฐ ์ฝ๋์ ๊ฐ๋ ์ ์ก๋ ๋ฐ ๋์์ด ๋๋ค.
- ๋ฐํ ํ์
์
// function getJSON(url: string): Promise<any>
async function getJSON(url: string) {
const response = await fetch(url);
const jsonPromise = response.json(); // ํ์
์ด Promise<any>
return jsonPromise;
}
# Item26. ํ์ ์ถ๋ก ์ ๋ฌธ๋งฅ์ด ์ด๋ป๊ฒ ์ฌ์ฉ๋๋์ง ์ดํดํ๊ธฐ
type Language = 'JavaScript' | 'TypeScript' | 'Python';
function setLanguage(language: Language) { /* ... */ }
// ์ธ๋ผ์ธ ํํ
setLanguage('JavaScript'); // ์ ์
// ์ฐธ์กฐ ํํ
let language = 'JavaScript';
setLanguage(language); // 'string' ํ์์ ์ธ์๋ 'Language' ํ์์ ๋งค๊ฐ๋ณ์์ ํ ๋น๋ ์ ์์ต๋๋ค.
- ์ ์ฝ๋์์ ์ธ๋ผ์ธ ํํ์์ ํ์
์คํฌ๋ฆฝํธ๋ ํจ์ ์ ์ธ์ ํตํด ๋งค๊ฐ๋ณ์๊ฐ
Language
ํ์ ์ด์ด์ผ ํ๋ค๋ ๊ฒ์ ์๊ณ ์๋ค.- ํด๋น ํ์
์ ๋ฌธ์์ด ๋ฆฌํฐ๋ด
'JavaScript'
๋ ํ ๋น ๊ฐ๋ฅํ๋ฏ๋ก ์ ์์ด๋ค. - ๊ทธ๋ฌ๋ ์ด ๊ฐ์ ๋ณ์๋ก ๋ถ๋ฆฌํด๋ด๋ฉด, ํ์ ์คํฌ๋ฆฝํธ๋ ํ ๋น ์์ ์ ํ์ ์ ์ถ๋ก ํ๋ค.
- ํด๋น ํ์
์ ๋ฌธ์์ด ๋ฆฌํฐ๋ด
- ์์ ๊ฐ์ ๋ฌธ์ ํด๊ฒฐ ๋ฐฉ๋ฒ์ผ๋ก ๋ ๊ฐ์ง๊ฐ ์๋ค.
- ์ฒซ ๋ฒ์งธ ํด๋ฒ์ ํ์
์ ์ธ์์
language
์ ๊ฐ๋ฅํ ๊ฐ์ ์ ํํ๋ ๊ฒ์ด๋ค.
let language: Language = 'JavaScript';
setLanguage(language);
- ๋ ๋ฒ์งธ ํด๋ฒ์
language
๋ฅผ ์์๋ก ๋ง๋๋ ๊ฒ์ด๋ค.
const language = 'JavaScript';
setLanguage(language);
- ์์ ๊ฐ์ ๊ณผ์ ์์ ์ฌ์ฉ๋๋ ๋ฌธ๋งฅ์ผ๋ก๋ถํฐ ๊ฐ์ ๋ถ๋ฆฌํ๋ค.
- ๋ฌธ๋งฅ๊ณผ ๊ฐ์ ๋ถ๋ฆฌํ๋ฉด ์ถํ์ ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ ๋ฅผ ๋ฐ์์ํฌ ์ ์๋ค.
- ์ด์ ๋ถํฐ ์ด๋ฌํ ๋ฌธ๋งฅ์ ์์ค๋ก ์ธํด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ ๋ช ๊ฐ์ง ๊ฒฝ์ฐ์, ์ด๋ฅผ ํด๊ฒฐํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด์.
# โญ๏ธ ํํ ์ฌ์ฉ ์ ์ฃผ์์
function panTo(where: [number, number]) { /* ... */ }
panTo([10, 20]); // ์ ์
const loc = [10, 20];
panTo(loc); // 'number[]' ํ์์ ์ธ์๋ '[number, number]' ํ์์ ๋งค๊ฐ๋ณ์์ ํ ๋น๋ ์ ์์ต๋๋ค.
- ํ์ ์ ์ธ์ ์ ๊ณตํ๋ ๋ฐฉ๋ฒ
const loc: [number, number] = [10, 20];
panTo(loc);
- '์์ ๋ฌธ๋งฅ' ์ ๊ณตํ๋ ๋ฐฉ๋ฒ
const
: ๋จ์ง ๊ฐ์ด ๊ฐ๋ฆฌํค๋ ์ฐธ์กฐ๊ฐ ๋ณํ์ง ์๋ ์์ ์์as const
: ๊ทธ ๊ฐ์ด ๋ด๋ถ๊น์ง ์์๋ผ๋ ์ฌ์ค์ ํ์ ์คํฌ๋ฆฝํธ์๊ฒ ์๋ฆผ
const loc = [10, 20] as const;
panTo(loc); // ~~~ 'readonly [10, 20]' ํ์์ 'readonly' ์ด๋ฉฐ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ํ์ '[number, number]'์ ํ ๋นํ ์ ์์ต๋๋ค.
- ์ ์ค๋ฅ๋ ์ ํํ ์ถ๋ก ํ ๋ด์ฉ์ด๋ค.
panTo
์ ํ์ ์๊ทธ๋์ฒ๋where
์ ๋ด์ฉ์ด ๋ถ๋ณ์ด๋ผ๊ณ ๋ณด์ฅํ์ง ์๋๋ค.- ์ฆ,
loc
๋งค๊ฐ๋ณ์๊ฐreadonly
ํ์ ์ด๋ฏ๋ก ๋์ํ์ง ์๋๋ค.
- ์ต์ ์ ํด๊ฒฐ์ฑ
: ํจ์์ ๋งค๊ฐ๋ณ์์ ํ์
์
readonly
์ง์
function panTo(where: readonly [number, number]) { /* ... */ }
const loc = [10, 20] as const;
panTo(loc);
as const
์ ๋จ์ - ๋ง์ฝ ํ์ ์ ์์ ์ค์๊ฐ ์๋ค๋ฉด (ex. ํํ์ ์ธ ๋ฒ์งธ ์์ ์ถ๊ฐ) ์ค๋ฅ๋ ํ์ ์ ์๊ฐ ์๋๋ผ ํธ์ถ๋๋ ๊ณณ์์ ๋ฐ์ํ๋ค๋ ๊ฒ์ด๋ค.
- ํนํ ์ฌ๋ฌ ๊ฒน ์ค์ฒฉ๋ ๊ฐ์ฒด์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค๋ฉด ๊ทผ๋ณธ์ ์ธ ์์ธ์ ํ์ ํ๊ธฐ ์ด๋ ต๋ค.
const loc = [10, 20, 30] as const;
panTo(loc); // 'readonly [10, 20, 30]' ํ์์ ์ธ์๋ 'readonly [number, number]' ํ์์ ๋งค๊ฐ๋ณ์์ ํ ๋น๋ ์ ์์ต๋๋ค.
// 'length' ์์ฑ์ ํ์์ด ํธํ๋์ง ์์ต๋๋ค.
// '3' ํ์์ '2' ํ์์ ํ ๋นํ ์ ์์ต๋๋ค.
# โญ๏ธ ๊ฐ์ฒด ์ฌ์ฉ ์ ์ฃผ์์
type Language = 'JavaScript' | 'TypeScript' | 'Python';
interface GovernedLanguage {
language: Language;
organization: string;
}
function complain(language: GovernedLanguage) { /* ... */ }
complain({ language: 'TypeScript', organization: 'Microsoft' }); // ์ ์
const ts = {
language: 'TypeScript',
organization: 'Microsoft',
};
complain(ts); // ~~'{ language: string; organization: string; }' ํ์์ ์ธ์๋ 'GovernedLanguage' ํ์์ ๋งค๊ฐ๋ณ์์ ํ ๋น๋ ์ ์์ต๋๋ค.
// 'language' ์์ฑ์ ํ์์ด ํธํ๋์ง ์์ต๋๋ค.
// 'string' ํ์์ 'Language' ํ์์ ํ ๋นํ ์ ์์ต๋๋ค.
ts
๊ฐ์ฒด์์language
์ ํ์ ์string
์ผ๋ก ์ถ๋ก ๋๋ค.- ์ด ๋ฌธ์ ๋ ํ์
์ ์ธ์ ์ถ๊ฐํ๊ฑฐ๋(
const ts: GovernedLanguage = ...
) ์์ ๋จ์ธ(as const
)์ ์ฌ์ฉํด ํด๊ฒฐํ ์ ์๋ค.
- ์ด ๋ฌธ์ ๋ ํ์
์ ์ธ์ ์ถ๊ฐํ๊ฑฐ๋(
# โญ๏ธ ์ฝ๋ฐฑ ์ฌ์ฉ ์ ์ฃผ์์
function callWithRandomNumbers(fn: (n1: number, n2: number) => void) {
fn(Math.random(), Math.random());
}
callWithRandomNumbers((a, b) => {
a; // ํ์
์ด number
b; // ํ์
์ด number
console.log(a + b);
})
callWithRandomNumbers
ํจ์์ ์ธ์๋ก ๋ค์ด๊ฐ๋ ์ฝ๋ฐฑ ํจ์๋ฅผ ์์๋ก ๋ฝ์๋ด๋ฉด ๋ฌธ๋งฅ์ด ์์ค๋๊ณnoImplicitAny
์ค๋ฅ๊ฐ ๋ฐ์ํ๊ฒ ๋๋ค.- ์ด๋ฐ ๊ฒฝ์ฐ๋ ๋งค๊ฐ๋ณ์์ ํ์ ๊ตฌ๋ฌธ์ ์ถ๊ฐํด์ ํด๊ฒฐํ ์ ์๋ค. ๋๋ ๊ฐ๋ฅํ ๊ฒฝ์ฐ ์ ์ฒด ํจ์ ํํ์์ ํ์ ์ ์ธ์ ์ ์ฉํ๋ ๊ฒ์ด๋ค.
const fn = (a: number, b: number) => {
console.log(a + b);
}
callWithRandomNumbers(fn);
# Item27. ํจ์ํ ๊ธฐ๋ฒ๊ณผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก ํ์ ํ๋ฆ ์ ์งํ๊ธฐ
- ํ์ ํ๋ฆ์ ๊ฐ์ ํ๊ณ , ๊ฐ๋ ์ฑ์ ๋์ด๊ณ , ๋ช ์์ ์ธ ํ์ ๊ตฌ๋ฌธ์ ํ์์ฑ์ ์ค์ด๊ธฐ ์ํด ์ง์ ๊ตฌํํ๊ธฐ๋ณด๋ค๋ ๋ด์ฅ๋ ํจ์ํ ๊ธฐ๋ฒ๊ณผ lodash ๊ฐ์ ์ ํธ๋ฆฌํฐ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
# Item28. ์ ํจํ ์ํ๋ง ํํํ๋ ํ์ ์ ์งํฅํ๊ธฐ
- ํจ๊ณผ์ ์ผ๋ก ํ์
์ ์ค๊ณํ๋ ค๋ฉด, ์ ํจํ ์ํ๋ง ํํํ ์ ์๋ ํ์
์ ๋ง๋ค์ด ๋ด๋ ๊ฒ์ด ๊ฐ์ฅ ์ค์ํ๋ค.
- ์ ํจํ ์ํ์ ๋ฌดํจํ ์ํ๋ฅผ ๋ ๋ค ํํํ๋ ํ์ ์ ํผ๋์ ์ด๋ํ๊ธฐ ์ฝ๊ณ ์ค๋ฅ๋ฅผ ์ ๋ฐํ๊ฒ ๋๋ค.
- ์ ํจํ ์ํ๋ง ํํํ๋ ํ์
์ ์งํฅํด์ผ ํ๋ค.
- ์ฝ๋๊ฐ ๊ธธ์ด์ง๊ฑฐ๋ ํํํ๊ธฐ ์ด๋ ต์ง๋ง ๊ฒฐ๊ตญ์ ์๊ฐ์ ์ ์ฝํ๊ณ ๊ณ ํต์ ์ค์ผ ์ ์๋ค.
# โญ๏ธ [์์] ํ์ด์ง ๋ด์ฉ ๋ก๋ ํ ํ๋ฉด์ ํ์ํ๋ ์ฝ๋
# ๐ before
interface State {
pageText: string;
isLoading: boolean;
error?: string;
}
function renderPage(state: State) {
if (state.error) {
return `Error! Unable to load ${currentPage}: ${state.error}`;
} else if (state.isLoading) {
return `Loading ${currentPage}...`;
}
return `<h1>${currentPage}</h1>\n${state.pageText}`;
}
async function changePage(state: State, newPage: string) {
state.isLoading = true;
try {
const response = await fetch(getUrlForPage(newPage));
if (!response.ok) {
throw new Error(`Unable to load ${newPage}: ${response.statusText}`);
}
const text = await response.text();
state.isLoading = false;
state.pageText = text;
} catch (e) {
state.error = '' + e;
}
}
- ์ ํจ์๋ค์ ๋ฌธ์ ์ ์ด ์กด์ฌํ๋ค.
- ์ํ ๊ฐ์ ๋ ๊ฐ์ง ์์ฑ์ด ๋์์ ์ ๋ณด๊ฐ ๋ถ์กฑํ๊ฑฐ๋(์์ฒญ์ด ์คํจํ ๊ฒ์ธ์ง ์ฌ์ ํ ๋ก๋ฉ ์ค์ธ์ง ์ ์ ์์), ๋ ๊ฐ์ง ์์ฑ์ด ์ถฉ๋(์ค๋ฅ์ด๋ฉด์ ๋์์ ๋ก๋ฉ ์ค์ผ ์ ์์)ํ ์ ์๋ค.
State
ํ์ ์isLoading
์ดtrue
์ด๊ณ ๋์์error
๊ฐ์ด ์กด์ฌํ๋ ๋ฌดํจํ ์ํ๋ฅผ ํ์ฉํ๋ค.- ๋ฌดํจํ ์ํ๊ฐ ์กด์ฌํ๋ฉด ์ ๋ ํจ์๋ฅผ ์ ๋๋ก ๊ตฌํํ ์ ์๋ค.
# ๐ after
- ๋คํธ์ํฌ ์์ฒญ ๊ณผ์ ๊ฐ๊ฐ์ ์ํ๋ฅผ ๋ช ์์ ์ผ๋ก ๋ชจ๋ธ๋ฆฌํ๋ ํ๊ทธ๋ ์ ๋์จ์ ์ฌ์ฉ
interface RequestPending {
state: 'pending';
}
interface RequestError {
state: 'error';
error: string;
}
interface RequestSuccess {
state: 'ok';
pageText: string;
}
type RequestState = RequestPending | RequestError | RequestSuccess;
interface State {
currentPage: string;
request: { [page: string]: RequestState };
}
function renderPage(state: State) {
const { currentPage } = state;
const requestState = state.requests[currentPage];
switch (requestState.state) {
case 'pending':
return `Loading ${currentPage}...`;
case 'error':
return `Error! Unable to load ${currentPage}: ${requestState.error}`;
case 'ok':
return `<h1>${currentPage}</h1>\n${state.pageText}`;
}
}
async function changePage(state: State, newPage: string) {
state.requests[newPage] = { state: 'pending' };
state.currentPage = newPage;
try {
const response = await fetch(getUrlForPage(newPage));
if (!response.ok) {
throw new Error(`Unable to load ${newPage}: ${response.statusText}`);
}
const text = await response.text();
state.requests[newPage] = { state: 'ok', pageText };
} catch (e) {
state.requests[newPage] = { state: 'error', error: '' + e };
}
}