๐ค Chapter 4: ํ์ ์ค๊ณ
๐ฅ ์์ดํ 28. ์ ํจํ ์ํ๋ง ํํํ๋ ํ์ ์ ์งํฅํ๊ธฐโ
ํจ๊ณผ์ ์ผ๋ก ํ์ ์ ์ค๊ณํ๋ ค๋ฉด, ์ ํจํ ์ํ๋ง ํํํ ์ ์๋ ํ์ ์ ๋ง๋ค์ด ๋ด๋ ๊ฒ์ด ๊ฐ์ฅ ์ค์ํฉ๋๋ค.
์น ์ ํ๋ฆฌ์ผ์ด์ ์ ๋ง๋ ๋ค๊ณ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค. ์ ํ๋ฆฌ์ผ์ด์ ์์ ํ์ด์ง๋ฅผ ์ ํํ๋ฉด, ํ์ด์ง์ ๋ด์ฉ์ ๋ก๋ํ๊ณ ํ๋ฉด์ ํ์ํฉ๋๋ค. ํ์ด์ง์ ์ํ๋ ๋ค์์ฒ๋ผ ์ค๊ณํ์ต๋๋ค.
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}`;
}
์ฝ๋๋ฅผ ์ดํด๋ณด๋ฉด ๋ถ๊ธฐ ์กฐ๊ฑด์ด ๋ช
ํํ ๋ถ๋ฆฌ๋์ด ์์ง ์๋ค๋ ๊ฒ์ ์ ์ ์์ต๋๋ค.
ํํธ ํ์ด์ง๋ฅผ ์ ํํ๋ changePage
ํจ์๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
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;
}
}
changePage
์๋ ๋ง์ ๋ฌธ์ ์ ์ด ์์ต๋๋ค. ๋ช ๊ฐ์ง ์ ๋ฆฌํด ๋ณด๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- ์ค๋ฅ๊ฐ ๋ฐ์ํ์ ๋
state.isLoading
์false
๋ก ์ค์ ํ๋ ๋ก์ง์ด ๋น ์ ธ ์์ต๋๋ค. state.error
๋ฅผ ์ด๊ธฐํํ์ง ์์๊ธฐ ๋๋ฌธ์, ํ์ด์ง ์ ํ ์ค์ ๋ก๋ฉ ๋ฉ์์ง ๋์ ๊ณผ๊ฑฐ์ ์ค๋ฅ ๋ฉ์์ง๋ฅผ ๋ณด์ฌ ์ฃผ๊ฒ ๋ฉ๋๋ค.- ํ์ด์ง ๋ก๋ฉ ์ค์ ์ฌ์ฉ์๊ฐ ํ์ด์ง๋ฅผ ๋ฐ๊ฟ ๋ฒ๋ฆฌ๋ฉด ์ด๋ค ์ผ์ด ๋ฒ์ด์ง์ง ์์ํ๊ธฐ ์ด๋ ต์ต๋๋ค. ์ ํ์ด์ง์ ์ค๋ฅ๊ฐ ๋จ๊ฑฐ๋, ์๋ต์ด ์ค๋ ์์์ ๋ฐ๋ผ ๋๋ฒ์งธ ํ์ด์ง๊ฐ ์๋ ์ฒซ ๋ฒ์งธ ํ์ด์ง๋ก ์ ํ๋ ์๋ ์์ต๋๋ค.
๋ฌธ์ ๋ ๋ฐ๋ก ์ํ ๊ฐ์ ๋ ๊ฐ์ง ์์ฑ์ด ๋์์ ์ ๋ณด๊ฐ ๋ถ์กฑํ๊ฑฐ๋, ๋ ๊ฐ์ง ์์ฑ์ด ์ถฉ๋ํ ์ ์๋ค๋ ๊ฒ์
๋๋ค. State
ํ์
์ isLoading
์ด true
์ด๋ฉด์ ๋์์ error
๊ฐ์ด ์ค์ ๋๋ ๋ฌดํจํ ์ํ๋ฅผ ํ์ฉํฉ๋๋ค. ๋ฌดํจํ ์ํ๊ฐ ์กด์ฌํ๋ฉด render()
์ changePage()
๋ ๋ค ์ ๋๋ก ๊ตฌํํ ์ ์๊ฒ ๋ฉ๋๋ค.
๋ค์์ ์ ํ๋ฆฌ์ผ์ด์
์ ์ํ๋ฅผ ์ข ๋ ์ ๋๋ก ํํํ ๋ฐฉ๋ฒ์
๋๋ค.
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;
requests: {[page: string]: RequestState};
}
์ด๋ฒ ์์ ๋ ์ํ๋ฅผ ๋ํ๋ด๋ ํ์
์ ์ฝ๋ ๊ธธ์ด๊ฐ ์๋ ๋ฐฐ ๊ธธ์ด์ง๊ธด ํ์ง๋ง, ๋ฌดํจํ ์ํ๋ฅผ ํ์ฉํ์ง ์๋๋ก ํฌ๊ฒ ๊ฐ์ ๋์์ต๋๋ค. ํ์ฌ ํ์ด์ง๋ ๋ฐ์ํ๋ ๋ชจ๋ ์์ฒญ์ ์ํ๋ก์, ๋ช
์์ ์ผ๋ก ๋ชจ๋ธ๋ง๋์์ต๋๋ค. ๊ทธ ๊ฒฐ๊ณผ๋ก ๊ฐ์ ๋ renderPage
์ changePage
ํจ์๋ ์ฝ๊ฒ ๊ตฌํํ ์ ์์ต๋๋ค.
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${requestState.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 pageText = await response.text();
state.requests[newPage] = { state: 'ok', pageText };
} catch (e) {
state.requests[newPage] = { state: 'error', error: '' + e };
}
}
์ด๋ฒ ์์ดํ ์ ์ฒ์์ ๋ฑ์ฅํ๋ ๋ชจํธํจ์ ์์ ํ ์ฌ๋ผ์ก์ต๋๋ค. ํ์ฌ ํ์ด์ง๊ฐ ๋ฌด์์ธ์ง ๋ช ํํ๋ฉฐ, ๋ชจ๋ ์์ฒญ์ ์ ํํ ํ๋์ ์ํ๋ก ๋ง์ ๋จ์ด์ง๋๋ค. ์์ฒญ์ด ์งํ ์ค์ธ ์ํ์์ ์ฌ์ฉ์๊ฐ ํ์ด์ง๋ฅผ ๋ณ๊ฒฝํ๋๋ผ๊ณ ๋ฌธ์ ์์ต๋๋ค. ๋ฌดํจ๊ฐ ๋ ์์ฒญ์ด ์คํ๋๊ธด ํ๊ฒ ์ง๋ง UI์๋ ์ํฅ์ ๋ฏธ์น์ง ์์ต๋๋ค.
ํ์ ์ ์ค๊ณํ ๋๋ ์ด๋ค ๊ฐ๋ค์ ํฌํจํ๊ณ ์ด๋ค ๊ฐ๋ค์ ์ ์ธํ ์ง ์ ์คํ๊ฒ ์๊ฐํด์ผ ํฉ๋๋ค. ์ ํจํ ์ํ๋ฅผ ํํํ๋ ๊ฐ๋ง ํ์ฉํ๋ค๋ฉด ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ฌ์์ง๊ณ ํ์ ์ฒดํฌ๊ฐ ์ฉ์ดํด์ง๋๋ค. ์ ํจํ ์ํ๋ง ํ์ฉํ๋ ๊ฒ์ ๋งค์ฐ ์ผ๋ฐ์ ์ธ ์์น์ ๋๋ค. ๋ฐ๋ฉด ํน์ ํ ์ํฉ์์ ์ง์ผ์ผํ ์์น๋ค๋ ์๋๋ฐ, 4์ฅ์ ๋ค๋ฅธ ์์ดํ ๋ค์์ ๋ค๋ฃจ๊ฒ ์ต๋๋ค.
์์ฝโ
- ์ ํจํ ์ํ์ ๋ฌดํจํ ์ํ๋ฅผ ๋ ๋ค ํํํ๋ ํ์ ์ ํผ๋์ ์ด๋ํ๊ธฐ ์ฝ๊ณ ์ค๋ฅ๋ฅผ ์ ๋ฐํ๊ฒ ๋ฉ๋๋ค.
- ์ ํจํ ์ํ๋ง ํํํ๋ ํ์ ์ ์งํฅํด์ผ ํฉ๋๋ค. ์ฝ๋๊ฐ ๊ธธ์ด์ง๊ฑฐ๋ ํํํ๊ธฐ ์ด๋ ต์ง๋ง ๊ฒฐ๊ตญ์ ์๊ฐ์ ์ ์ฝํ๊ณ ๊ณ ํต์ ์ค์ผ ์ ์์ต๋๋ค.
๐ฅ ์์ดํ 29. ์ฌ์ฉํ ๋๋ ๋๊ทธ๋ฝ๊ฒ, ์์ฑํ ๋๋ ์๊ฒฉํ๊ฒโ
ํจ์์ ๋งค๊ฐ๋ณ์๋ ํ์ ์ ๋ฒ์๊ฐ ๋์ด๋ ๋์ง๋ง, ๊ฒฐ๊ณผ๋ฅผ ๋ฐํํ ๋๋ ์ผ๋ฐ์ ์ผ๋ก ํ์ ์ ๋ฒ์๊ฐ ๋ ๊ตฌ์ฒด์ ์ด์ด์ผ ํฉ๋๋ค.
์์ P. 163 ~ P. 166 ์ฐธ๊ณ
์์ฝโ
- ๋ณดํต ๋งค๊ฐ๋ณ์ ํ์ ์ ๋ฐํ ํ์ ์ ๋นํด ๋ฒ์๊ฐ ๋์ ๊ฒฝํฅ์ด ์์ต๋๋ค. ์ ํ์ ์์ฑ๊ณผ ์ ๋์จ ํ์ ์ ๋ฐํ ํ์ ๋ณด๋ค ๋งค๊ฐ๋ณ์ ํ์ ์ ๋ ์ผ๋ฐ์ ์ ๋๋ค.
- ๋งค๊ฐ๋ณ์์ ๋ฐํ ํ์ ์ ์ฌ์ฌ์ฉ์ ์ํด์ ๊ธฐ๋ณธ ํํ(๋ฐํ ํ์ )์ ๋์จํ ํํ(๋งค๊ฐ๋ณ์ ํ์ )๋ฅผ ๋์ ํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๐ฅ ์์ดํ 30. ๋ฌธ์์ ํ์ ์ ๋ณด๋ฅผ ์ฐ์ง ์๊ธฐโ
๋ค์ ์ฝ๋์์ ์๋ชป๋ ๋ถ๋ถ์ ์ฐพ์๋ณด๊ฒ ์ต๋๋ค.
/**
* ์ ๊ฒฝ์(foreground) ๋ฌธ์์ด์ ๋ฐํํฉ๋๋ค.
* 0 ๊ฐ ๋๋ 1 ๊ฐ์ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ์ต๋๋ค.
* ๋งค๊ฐ๋ณ์๊ฐ ์์ ๋๋ ํน์ ํ์ด์ง์ ์ ๊ฒฝ์์ ๋ฐํํฉ๋๋ค.
**/
function getForegroundColor(page?: string) {
return page === 'login' ? { r: 127, g: 127, b: 127 } : { r: 0, g: 0, b: 0 };
}
์ฝ๋์ ์ฃผ์์ ์ ๋ณด๊ฐ ๋ง์ง ์์ต๋๋ค. ๋ ์ค ์ด๋ ๊ฒ์ด ์ณ์์ง ํ๋จํ๊ธฐ์๋ ์ ๋ณด๊ฐ ๋ถ์กฑํ๋ฉฐ, ์๋ชป๋ ์ํ๋ผ๋ ๊ฒ๋ง์ ๋ถ๋ช
ํฉ๋๋ค.
์์ ์์ ์์ ์๋๋ ๋์์ด ์ฝ๋์ ์ ๋๋ก ๋ฐ์๋๊ณ ์๋ค๊ณ ๊ฐ์ ํ๋ฉด, ์ฃผ์์๋ ์ธ ๊ฐ์ง ๋ฌธ์ ์ ์ด ์์ต๋๋ค.
- ํจ์๊ฐ
string
ํํ์ ์๊น์ ๋ฐํํ๋ค๊ณ ์ ํ ์์ง๋ง ์ค์ ๋ก๋{ r, g, b }
๊ฐ์ฒด๋ฅผ ๋ฐํํฉ๋๋ค. - ์ฃผ์์๋ ํจ์๊ฐ 0๊ฐ ๋๋ 1๊ฐ์ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ๋๋ค๊ณ ์ค๋ช ํ๊ณ ์์ง๋ง, ํ์ ์๊ทธ๋์ฒ๋ง ๋ณด์๋ ๋ช ํํ๊ฒ ์ ์ ์๋ ์ ๋ณด์ ๋๋ค.
- ๋ถํ์ํ๊ฒ ์ฅํฉํฉ๋๋ค. ํจ์ ์ ์ธ๊ณผ ๊ตฌํ์ฒด๋ณด๋ค ์ฃผ์์ด ๋ ๊น๋๋ค.
ํ์
์คํฌ๋ฆฝํธ์ ํ์
๊ตฌ๋ฌธ ์์คํ
์ ๊ฐ๊ฒฐํ๊ณ , ๊ตฌ์ฒด์ ์ด๋ฉฐ, ์ฝ๊ฒ ์ฝ์ ์ ์๋๋ก ์ค๊ณ๋์์ต๋๋ค. ํจ์์ ์
๋ ฅ๊ณผ ์ถ๋ ฅ์ ํ์
์ ์ฝ๋๋ก ํํํ๋ ๊ฒ์ด ์ฃผ์๋ณด๋ค ๋ ๋์ ๋ฐฉ๋ฒ์ด๋ผ๋ ๊ฒ์ ์๋ช
ํฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ํ์
๊ตฌ๋ฌธ์ ํ์
์คํฌ๋ฆฝํธ ์ปดํ์ผ๋ฌ๊ฐ ์ฒดํฌํด ์ฃผ๊ธฐ ๋๋ฌธ์, ์ ๋๋ก ๊ตฌํ์ฒด์์ ์ ํฉ์ฑ์ด ์ด๊ธ๋์ง ์์ต๋๋ค.
๋๊ตฐ๊ฐ ๊ฐ์ ํ์ง ์๋ ์ด์ ์ฃผ์์ ์ฝ๋์ ๋๊ธฐํ๋์ง ์์ต๋๋ค. ๊ทธ๋ฌ๋ ํ์
๊ตฌ๋ฌธ์ ํ์
์คํฌ๋ฆฝํธ ํ์
์ฒด์ปค๊ฐ ํ์
์ ๋ณด๋ฅผ ๋๊ธฐํํ๋๋ก ๊ฐ์ ํฉ๋๋ค. ์ฃผ์ ๋์ ํ์
์ ๋ณด๋ฅผ ์์ฑํ๋ค๋ฉด ์ฝ๋๊ฐ ๋ณ๊ฒฝ๋๋ค ํ๋๋ผ๋ ์ ๋ณด๊ฐ ์ ํํ ๋๊ธฐํ๋ฉ๋๋ค.
์ฃผ์์ ๋ค์๊ณผ ๊ฐ์ด ๊ฐ์ ํ ์ ์์ต๋๋ค.
// ์ ํ๋ฆฌ์ผ์ด์
๋๋ ํน์ ํ์ด์ง์ ์ ๊ฒฝ์์ ๊ฐ์ ธ์ต๋๋ค.
function getForegroundColor(page?: string): Color {
// ...
}
ํน์ ๋งค๊ฐ๋ณ์๋ฅผ ์ค๋ช
ํ๊ณ ์ถ๋ค๋ฉด JSDoc
์ @param
๊ตฌ๋ฌธ์ ์ฌ์ฉํ๋ฉด ๋ฉ๋๋ค.
๊ฐ์ ๋ณ๊ฒฝํ์ง ์๋๋ค๊ณ ์ค๋ช
ํ๋ ์ฃผ์๋ ์ข์ง ์์ต๋๋ค. ๋ํ ๋งค๊ฐ๋ณ์๋ฅผ ๋ณ๊ฒฝํ์ง ์๋๋ค๋ ์ฃผ์๋ ์ฌ์ฉํ์ง ์๋ ๊ฒ์ด ์ข์ต๋๋ค.
// nums๋ฅผ ๋ณ๊ฒฝํ์ง ์์ต๋๋ค.
function sort(nums: number[]) { /* ... */ }
๊ทธ ๋์ , readonly
๋ก ์ ์ธํ์ฌ ํ์
์คํฌ๋ฆฝํธ๊ฐ ๊ท์น์ ๊ฐ์ ํ ์ ์๊ฒ ํ๋ฉด ๋ฉ๋๋ค.
function sort(nums: readonly number[]) { /* ... */ }
์ฃผ์์ ์ ์ฉํ ๊ท์น์ ๋ณ์๋ช
์๋ ๊ทธ๋๋ก ์ ์ฉํ ์ ์์ต๋๋ค. ๋ณ์๋ช
์ ํ์
์ ๋ณด๋ฅผ ๋ฃ์ง ์๋๋ก ํฉ๋๋ค. ์๋ฅผ ๋ค์ด ๋ณ์๋ช
์ ageNum
์ผ๋ก ํ๋ ๊ฒ๋ณด๋ค๋ age
๋ก ํ๊ณ , ๊ทธ ํ์
์ด number
์์ ๋ช
์ํ๋ ๊ฒ ์ข์ต๋๋ค.
๊ทธ๋ฌ๋ ๋จ์๊ฐ ์๋ ์ซ์๋ค์ ์์ธ์
๋๋ค. ๋จ์๊ฐ ๋ฌด์์ธ์ง ํ์คํ์ง ์๋ค๋ฉด ๋ณ์๋ช
๋๋ ์์ฑ ์ด๋ฆ์ ๋จ์๋ฅผ ํฌํจํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด timeMs
๋ time
๋ณด๋ค ํจ์ฌ ๋ช
ํํ๊ณ temperatureC
๋ temperature
๋ณด๋ค ํจ์ฌ ๋ช
ํํฉ๋๋ค.
๐ฅ ์์ดํ
31. ํ์
์ฃผ๋ณ์ null
๊ฐ ๋ฐฐ์นํ๊ธฐโ
๊ฐ์ด ์ ๋ถ null
์ด๊ฑฐ๋ ์ ๋ถ null
์ด ์๋ ๊ฒฝ์ฐ๋ก ๋ถ๋ช
ํ ๊ตฌ๋ถ๋๋ค๋ฉด, ๊ฐ์ด ์์ฌ ์์ ๋๋ณด๋ค ๋ค๋ฃจ๊ธฐ ์ฝ์ต๋๋ค. ํ์
์ null
์ ์ถ๊ฐํ๋ ๋ฐฉ์์ผ๋ก ์ด๋ฌํ ๊ฒฝ์ฐ๋ฅผ ๋ชจ๋ธ๋งํ ์ ์์ต๋๋ค.
์ซ์๋ค์ ์ต์ ๊ฐ๊ณผ ์ต๋๊ฐ์ ๊ณ์ฐํ๋ extent
ํจ์๋ฅผ ๊ฐ์ ํด ๋ณด๊ฒ ์ต๋๋ค.
function extent(nums: number[]) {
let min, max;
for (const num of nums) {
if (!min) {
min = num;
max = num;
} else {
min = Math.min(min, num);
max = Math.max(max, num);
}
}
return [min, max];
}
์ด ์ฝ๋๋ ํ์
์ฒด์ปค๋ฅผ ํต๊ณผํ๊ณ (strictNullChecks
์์ด), ๋ฐํ ํ์
์ number[]
๋ก ์ถ๋ก ๋ฉ๋๋ค. ๊ทธ๋ฌ๋ ์ฌ๊ธฐ์๋ ๋ฒ๊ทธ์ ํจ๊ป ์ค๊ณ์ ๊ฒฐํจ์ด ์์ต๋๋ค.
- ์ต์๊ฐ์ด๋ ์ต๋๊ฐ์ด 0์ธ ๊ฒฝ์ฐ, ๊ฐ์ด ๋ง์์์ ธ ๋ฒ๋ฆฝ๋๋ค. ์๋ฅผ ๋ค์ด,
extent([0, 1, 2])
์ ๊ฒฐ๊ณผ๋[0, 2]
๊ฐ ์๋๋ผ[1, 2]
๊ฐ ๋ฉ๋๋ค. nums
๋ฐฐ์ด์ด ๋น์ด ์๋ค๋ฉด ํจ์๋[undefined, undefined]
๋ฅผ ๋ฐํํฉ๋๋ค.
strictNullChecks
์ค์ ์ ์ผ๋ฉด ์์ ๋ ๊ฐ์ง ๋ฌธ์ ์ ์ด ๋๋ฌ๋ฉ๋๋ค.
function extent(nums: number[]) {
let min, max;
for (const num of nums) {
if (!min) {
min = num;
max = num;
} else {
min = Math.min(min, num);
max = Math.max(max, num);
// ~~~ 'number | undefined' ํ์์ ์ธ์๋ 'number' ํ์์ ๋งค๊ฐ๋ณ์์ ํ ๋น๋ ์ ์์ต๋๋ค.
}
}
return [min, max];
}