# ๐ Item19 ~ 23
# Item19. ์ถ๋ก ๊ฐ๋ฅํ ํ์ ์ ์ฌ์ฉํด ์ฅํฉํ ์ฝ๋ ๋ฐฉ์งํ๊ธฐ
# (1) ํ์ ์ถ๋ก ์ฅ์
- ํ์
์คํฌ๋ฆฝํธ๋ฅผ ์ฒ์ ์ ํ ๊ฐ๋ฐ์๊ฐ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๋ฅผ ํฌํ
ํ ๋ ๊ฐ์ฅ ๋จผ์ ํ๋ ์ผ์ ํ์
๊ตฌ๋ฌธ์ ๋ฃ๋ ๊ฒ์ด๋ค.
- ๋ชจ๋ ๋ณ์๋ฅผ ์ ์ธํ ๋๋ง๋ค ํ์ ์ ๋ช ์ํด์ผ ํ๋ค๊ณ ์๊ฐํ์ง๋ง ํ์ ์คํฌ๋ฆฝํธ์ ๋ง์ ํ์ ๊ตฌ๋ฌธ์ ์ฌ์ค ๋ถํ์ํ๋ค.
- ํ์ ์ด ์ถ๋ก ์ด ๋๋ค๋ฉด ๋ช ์์ ํ์ ๊ตฌ๋ฌธ์ ํ์ํ์ง ์๋๋ค.
let x: number = 12;
let x = 12; // ํด๋น ์ฝ๋๋ฅผ ๋ง์ฐ์ค๋ฅผ ์ฌ๋ฆฌ๋ฉด ํ์
์ด number๋ก ์ด๋ฏธ ์ถ๋ก ๋จ
- ํ์ ์ถ๋ก ๋๋ฉด ๋ฆฌํฉํ ๋ง ์ญ์ ์ฉ์ดํด์ง๋ค.
interface Product {
id: string;
name: string;
price: number;
}
function logProduct(product: Product) {
const id: number = product.id; // ๋ง์ฝ ์ด์ ๊ฐ์ด ์์ฑํ๋ฉด ํ์
์ค๋ฅ๊ฐ ๋ฐ์ํ ๊ฒ์ด๋ค.
const name: string = product.name;
const price: number = product.price;
console.log(id, name, price);
}
- ์ฐธ๊ณ ๋ก ์ ์ฝ๋ ๋ณด๋ค๋ ๋น๊ตฌ์กฐํ ํ ๋น๋ฌธ์ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ ์ข๋ค.
function logProduct(product: Product) {
const { id, name, price } = product;
console.log(id, name, price);
}
# (2) ๋ฌด์กฐ๊ฑด ๋ชจ๋ ๋ณ์์ ํ์ ์ ์ ์ํ์ง ๋ง์
ํ์ ์คํฌ๋ฆฝํธ๋ ์ต์ข ์ฌ์ฉ์ฒ๊น์ง ๊ณ ๋ คํ์ฌ ํ์ ์ ์ถ๋ก ํ์ง ์๋๋ค.
- ํ์ ์คํฌ๋ฆฝํธ์์ ๋ณ์์ ํ์ ์ ์ผ๋ฐ์ ์ผ๋ก ์ฒ์ ๋ฑ์ฅํ ๋ ๊ฒฐ์ ๋๋ค.
์ด์์ ์ธ ํ์ ์คํฌ๋ฆฝํธ ์ฝ๋๋ ํจ์/๋ฉ์๋ ์๊ทธ๋์ฒ์ ํ์ ๊ตฌ๋ฌธ์ ํฌํจํ์ง๋ง, ํจ์ ๋ด์์ ์์ฑ๋ ์ง์ญ ๋ณ์์๋ ํ์ ๊ตฌ๋ฌธ์ ๋ฃ์ง ์๋๋ค.
- ํ์ ๊ตฌ๋ฌธ์ ์๋ตํ์ฌ ๋ฐฉํด๋๋ ๊ฒ๋ค์ ์ต์ํํ๊ณ ์ฝ๋๋ฅผ ์ฝ๋ ์ฌ๋์ด ๊ตฌํ ๋ก์ง์ ์ง์คํ ์ ์๊ฒ ํ๋ ๊ฒ์ด ์ข๋ค.
๋ณดํต ํ์ ์ ๋ณด๊ฐ ์๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์์, ์ฝ๋ฐฑ ํจ์์ ๋งค๊ฐ๋ณ์ ํ์ ์ ์๋์ผ๋ก ์ถ๋ก ๋๋ค.
// Don't!
app.get('/health', (request: express.Request, response: express.Response) => {
response.send('OK');
})
// Do!
app.get('/health', (request, response) => {
response.send('OK');
})
# (3) ๊ฐ์ฒด ๋ฆฌํฐ๋ด ์ ์ํ ๋ ํ์ ์ถ๋ก
- ํ์ ์ด ์ถ๋ก ๋ ์ ์์์๋ ์ฌ์ ํ ํ์ ์ ๋ช ์ํ๊ณ ์ถ์ ์ํฉ์ด ์กด์ฌํ๋ค. ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ์ ์ํ ๋๋ฅผ ์ดํด๋ณด์.
const elmo: Product = {
name: 'Elmo',
id: '12345',
price: 28.99,
}
- ์์ ๊ฐ์ด ํ์
์ ๋ช
์ํ๋ฉด ์์ฌ ์์ฑ ์ฒดํฌ๊ฐ ๋์ํ๋ค.
- ์์ฌ ์์ฑ ์ฒดํฌ๋ ํนํ ์ ํ์ ์์ฑ์ด ์๋ ํ์ ์ ์คํ ๊ฐ์ ์ค๋ฅ๋ฅผ ์ก๋ ๋ฐ ํจ๊ณผ์ ์ด๋ค.
- ๊ทธ๋ฆฌ๊ณ ๋ณ์๊ฐ ์ฌ์ฉ๋๋ ์๊ฐ์ด ์๋ ํ ๋นํ๋ ์์ ์ ์ค๋ฅ๊ฐ ํ์๋๋๋ก ํด์ค๋ค.
- ๋ง์ฝ ํ์
๊ตฌ๋ฌธ์ ์ ๊ฑฐํ๋ค๋ฉด ์์ฌ ์์ฑ ์ฒดํฌ๊ฐ ๋์ํ์ง ์๊ณ , ๊ฐ์ฒด๋ฅผ ์ ์ธํ ๊ณณ์ด ์๋๋ผ ๊ฐ์ฒด๊ฐ ์ฌ์ฉ๋๋ ๊ณณ์์ ํ์
์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
- ๊ทธ๋ฌ๋ ํ์ ๊ตฌ๋ฌธ์ ์ ๋๋ก ๋ช ์ํ๋ค๋ฉด, ์ค์ ๋ก ์ค์๊ฐ ๋ฐ์ํ ๋ถ๋ถ์ ์ค๋ฅ๋ฅผ ํ์ํด์ค๋ค.
const elmo = {
name: 'Elmo',
id: '12345',
price: 28.99,
}
logProduct(elmo); // ์ฌ๊ธฐ์ ์ค๋ฅ ๋ฐ์!
# (4) ๋ฐํ ํ์ ๋ช ์์ ์ฅ์
# โญ๏ธ ์ค๋ฅ ๋ฐฉ์ง
- ํจ์์ ๋ฐํ์๋ ํ์
์ ๋ช
์ํ์ฌ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ ์ ์๋ค.
- ํ์ ์ถ๋ก ์ด ๊ฐ๋ฅํ ์ง๋ผ๋ ๊ตฌํ์์ ์ค๋ฅ๊ฐ ํจ์๋ฅผ ํธ์ถํ ๊ณณ๊น์ง ์ํฅ์ ๋ฏธ์น์ง ์๋๋ก ํ๊ธฐ ์ํด ํ์ ๊ตฌ๋ฌธ์ ๋ช ์ํ๋ ๊ฒ ์ข๋ค.
const cache: { [ticker: string]: number } = {};
function getQuote(ticker: string) {
if (ticker in cache) {
return cache[ticker];
}
return fetch(`https://quotes.example.com/?q=${ticker}`)
.then(response => response.json())
.then(quote => {
cache[ticker] = quote;
return quote;
});
}
- ์ ์ฝ๋์๋ ์ค๋ฅ๊ฐ ์กด์ฌํ๋๋ฐ
getQuote
๋ ํญ์Promise
๋ฅผ returnํ๋ฏ๋ก if ๊ตฌ๋ฌธ์๋cache[ticker]
๊ฐ ์๋๋ผPromise.resolve(cache[ticker])
๊ฐ ๋ฐํ๋๋๋ก ํด์ผ ํ๋ค.- ์คํํด๋ณด๋ฉด ์ค๋ฅ๋
getQuote
๋ด๋ถ๊ฐ ์๋getQuote
๋ฅผ ํธ์ถํ๋ ์ฝ๋์์ ๋ฐ์ํ๋ค.
- ์คํํด๋ณด๋ฉด ์ค๋ฅ๋
// ํจ์ ํธ์ถ๋ถ
getQuote('MSFT').then(considerBuying);
// ~~~ 'number | Promise<any>' ํ์์ 'then' ์์ฑ์ด ์์ต๋๋ค.
// 'number' ํ์์ 'then' ์์ฑ์ด ์์ต๋๋ค.
- ์ด ๋ ์๋๋ ๋ฐํ ํ์
(
Promise<number>
)์ ๋ช ์ํ๋ค๋ฉด, ์ ํํ ์์น์ ์ค๋ฅ๊ฐ ํ์๋๋ค.
const cache: { [ticker: string]: number } = {};
function getQuote(ticker: string): Promise<number> {
if (ticker in cache) {
return cache[ticker]; // 'number' ํ์์ 'Promise<number>' ํ์์ ํ ๋นํ ์ ์์ต๋๋ค.
}
}
- ๋ฐํ ํ์
์ ๋ช
์ํ๋ฉด, ๊ตฌํ์์ ์ค๋ฅ๊ฐ ์ฌ์ฉ์ ์ฝ๋์ ์ค๋ฅ๋ก ํ์๋์ง ์๋๋ค.
Promise
์ ๊ด๋ จ๋ ํน์ ์ค๋ฅ๋ฅผ ํผํ๋ ๋ฐ๋async
ํจ์๊ฐ ํจ๊ณผ์ ์ด๋ค.
# โญ๏ธ ํจ์์ ๋ํด ๋์ฑ ๋ช ํํ๊ฒ ์ ์ ์์
- ๋ฐํ ํ์
์ ๋ช
์ํ๋ ค๋ฉด ๊ตฌํํ๊ธฐ ์ ์ ์
๋ ฅ ํ์
๊ณผ ์ถ๋ ฅ ํ์
์ด ๋ฌด์์ธ์ง ์์์ผ ํ๋ค.
- ์ถํ์ ์ฝ๋๊ฐ ์กฐ๊ธ ๋ณ๊ฒฝ๋์ด๋ ๊ทธ ํจ์์ ์๊ทธ๋์ฒ๋ ์ฝ๊ฒ ๋ฐ๋์ง ์๋๋ค.
- ์ ์ฒด ํ์ ์๊ทธ๋์ฒ๋ฅผ ๋จผ์ ์์ฑํ๋ฉด ๊ตฌํ์ ๋ง์ถ์ด ์ฃผ๋จน๊ตฌ๊ตฌ์์ผ๋ก ์๊ทธ๋์ฒ๊ฐ ์์ฑ๋๋ ๊ฒ์ ๋ฐฉ์งํ๊ณ ์ํ๋ ๋ชจ์์ ์ป๊ฒ ๋๋ค.
# โญ๏ธ ๋ช ๋ช ๋ ํ์ ์ ์ฌ์ฉํ๊ธฐ ์ํด์
interface Vector2D {
x: number;
y: number;
}
function add(a: Vector2D, b: Vector2D) {
return {
x: a.x + b.x,
y: a.y + b.y,
}
}
- ์์ ๊ฐ์ด ๋ฐํ ํ์
์ ๋ช
์ํ์ง ์์ ๊ฒฝ์ฐ
add
ํจ์์ ๋ฐํ ํ์ ์{ x: number; y: number; }
๋ก ์ถ๋ก ๋๋ค.- ์ด๋ฐ ๊ฒฝ์ฐ
Vector2D
์ ํธํ๋์ง๋ง, ์ ๋ ฅ์ดVector2D
์ธ๋ฐ ๋ฐํด ์ถ๋ ฅ์Vector2D
๊ฐ ์๋๋ฏ๋ก ์ฌ์ฉ์ ์ ์ฅ์์ ๋นํฉ์ค๋ฌ์ธ ์ ์๋ค.
- ์ด๋ฐ ๊ฒฝ์ฐ
- ๋ฐํ ํ์
์ ๋ช
์ํ๋ฉด ๋์ฑ ์ง๊ด์ ์ธ ํํ์ด ๋๋ค.
- ๊ทธ๋ฆฌ๊ณ ๋ฐํ ๊ฐ์ ๋ณ๋์ ํ์
์ผ๋ก ์ ์ํ๋ฉด ํ์
์ ๋ํ ์ฃผ์์ ์์ฑํ ์ ์์ด์, ๋์ฑ ์์ธํ ์ค๋ช
์ด ๊ฐ๋ฅํ๋ค.(feat.
TSDoc
) - ์ถ๋ก ๋ ๋ฐํ ํ์ ์ด ๋ณต์กํด์ง์๋ก ๋ช ๋ช ๋ ํ์ ์ ์ ๊ณตํ๋ ์ด์ ์ ์ปค์ง๋ค.
- ๊ทธ๋ฆฌ๊ณ ๋ฐํ ๊ฐ์ ๋ณ๋์ ํ์
์ผ๋ก ์ ์ํ๋ฉด ํ์
์ ๋ํ ์ฃผ์์ ์์ฑํ ์ ์์ด์, ๋์ฑ ์์ธํ ์ค๋ช
์ด ๊ฐ๋ฅํ๋ค.(feat.
- ๋ฆฐํฐ๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค๋ฉด
eslint
๊ท์น ์คno-inferrable-types
์ ์ฌ์ฉํด์ ์์ฑ๋ ๋ชจ๋ ํ์ ๊ตฌ๋ฌธ์ด ์ ๋ง๋ก ํ์ํ์ง ํ์ธํ ์ ์๋ค.
# Item20. ๋ค๋ฅธ ํ์ ์๋ ๋ค๋ฅธ ๋ณ์ ์ฌ์ฉํ๊ธฐ
- ๋ค๋ฅธ ํ์
์๋ ๋ณ๋์ ๋ณ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ๋ฐ๋์งํ ์ด์
- ์๋ก ๊ด๋ จ์ด ์๋ ๋ ๊ฐ์ ๊ฐ์ ๋ถ๋ฆฌํ๋ค.
- ๋ณ์๋ช ์ ๋ ๊ตฌ์ฒด์ ์ผ๋ก ์ง์ ์ ์๋ค.
- ํ์ ์ถ๋ก ์ ํฅ์์ํค๋ฉฐ, ํ์ ๊ตฌ๋ฌธ์ด ๋ถํ์ํด์ง๋ค.
- ํ์
์ด ์ข ๋ ๊ฐ๊ฒฐํด์ง๋ค. (ex.
string | number
๋์string
๊ณผnumber
๋ฅผ ์ฌ์ฉ) let
๋์const
๋ก ๋ณ์๋ฅผ ์ ์ธํ๊ฒ ๋๋ค.const
๋ก ๋ณ์๋ฅผ ์ ์ธํ๋ฉด ์ฝ๋๊ฐ ๊ฐ๊ฒฐํด์ง๊ณ , ํ์ ์ฒด์ปค๊ฐ ํ์ ์ ์ถ๋ก ํ๊ธฐ์๋ ์ข๋ค.
- ๋ณ์์ ๊ฐ์ ๋ฐ๋ ์ ์์ง๋ง, ํ์ ์ ์ผ๋ฐ์ ์ผ๋ก ๋ฐ๋์ง ์๋๋ค.
- ํผ๋์ ๋ง๊ธฐ ์ํด ํ์ ์ด ๋ค๋ฅธ ๊ฐ์ ๋ค๋ฃฐ ๋์๋ ๋ณ์๋ฅผ ์ฌ์ฌ์ฉํ์ง ์๋๋ก ํ๋ค.
# Item21. ํ์ ๋ํ๊ธฐ
# (1) ํ์ ๋ํ๊ธฐ ๊ณผ์
- ํ์ ๋ํ๊ธฐ ๊ณผ์ ์ ์ง์ ๋ ๋จ์ผ ๊ฐ์ ๊ฐ์ง๊ณ ํ ๋น ๊ฐ๋ฅํ ๊ฐ๋ค์ ์งํฉ์ ์ ์ถํ๋ ๊ณผ์ ์ด๋ค.
interface Vector3 {
x: number;
y: number;
z: number;
}
function getComponent(vector: Vector3, axis: 'x' | 'y' | 'z') {
return vector[axis];
}
let x = 'x';
let vec = {x: 10, y: 20, z: 30};
getComponent(vec, x); // ~ 'string' ํ์์ ์ธ์๋ '"x" | "y" | "z"' ํ์์ ๋งค๊ฐ๋ณ์์ ํ ๋นํ ์ ์์ต๋๋ค.
- ์ ์ฝ๋์์ ๋ณด์๋ค์ํผ
getComponent
ํจ์๋ ๋ ๋ฒ์งธ ๋งค๊ฐ๋ณ์์"x" | "y" | "z"
ํ์ ์ ๊ธฐ๋ํ์ง๋ง,x
์ ํ์ ์ ํ ๋น ์์ ์ ๋ํ๊ธฐ๊ฐ ๋์ํด์string
์ผ๋ก ์ถ๋ก ๋์๋ค.string
ํ์ ์"x" | "y" | "z"
ํ์ ์ ํ ๋น์ด ๋ถ๊ฐ๋ฅํ๋ฏ๋ก ์ค๋ฅ๊ฐ ๋ ๊ฒ์ด๋ค.
- ํ์ ์คํฌ๋ฆฝํธ๊ฐ ์๋ฌด๋ฆฌ ์๋ฆฌํ๋๋ผ๋ ์ฌ๋์ ๋ง์๊น์ง ์ฝ์ ์๋ ์๊ณ ์ถ์ธกํ ๋ต์ด ํญ์ ์ณ์ ์๋ ์๋ค.
# (2) ํ์ ๋ํ๊ธฐ ๊ณผ์ ์ ์ ์ดํ๊ธฐ
# โญ๏ธ const
๋ก ๋ณ์ ์ ์ธํ๊ธฐ
let
๋์const
๋ก ๋ณ์๋ฅผ ์ ์ธํ๋ฉด ๋ ์ข์ ํ์ ์ด ๋๋ค.- ์ค์ ๋ก ์ ์ฝ๋์์ ๋ฐ์ํ ์ค๋ฅ๋ฅผ
const
๋ก ์์ฑํ๋ฉด ํด๊ฒฐ๋๋ค.
const x = 'x'; // ํ์
์ด "x"
let vec = {x: 10, y: 20, z: 30};
getComponent(vec, x); // ์ ์
- ์ด์
x
๊ฐ์ ์ฌํ ๋น๋ ์ ์์ผ๋ฏ๋ก ํ์ ์คํฌ๋ฆฝํธ๋ ์์ฌ์ ์ฌ์ง ์์ด ๋ ์ข์ ํ์ ("x"
)์ผ๋ก ์ถ๋ก ํ ์ ์๋ค.- ๊ทธ๋ฆฌ๊ณ ๋ฌธ์์ด ๋ฆฌํฐ๋ด ํ์
"x"
์"x" | "y" | "z"
์ ํ ๋น ๊ฐ๋ฅํ๋ฏ๋ก ์ฝ๋๊ฐ ํ์ ์ฒด์ปค๋ฅผ ํต๊ณผํ๋ค.
- ๊ทธ๋ฆฌ๊ณ ๋ฌธ์์ด ๋ฆฌํฐ๋ด ํ์
- ๊ทธ๋ฌ๋
const
๊ฐ ๋ง๋ฅ์ ์๋๋ค! ๊ฐ์ฒด์ ๋ฐฐ์ด์ ๊ฒฝ์ฐ์๋ ์ฌ์ ํ ๋ฌธ์ ๊ฐ ์๋ค.- ํํ ํ์ ์ ์ถ๋ก ํด์ผ ํ ์ง, ์์๋ค์ ์ด๋ค ํ์ ์ผ๋ก ์ถ๋ก ํด์ผ ํ ์ง ์ ์ ์๋ค.
const v = {
x: 1,
};
v.x = 3;
v.x = '3';
v.y = 4;
v.name = 'JS';
- ์ ์ฝ๋๋ ์๋ฐ์คํฌ๋ฆฝํธ์์ ์ ์์ ์ผ๋ก ๋์ํ๋ค.
v
๊ฐ์ ๊ตฌ์ฒด์ ์ผ๋ก ์ ์ํ๋ฉด{readonly x: 1}
์ด๋ค. ์กฐ๊ธ ์ถ์์ ์ผ๋ก๋{x: number}
๊ฐ ๋๊ณ ๊ฐ์ฅ ์ถ์์ ์ด๋ผ๋ฉด{[key: string]: number}
๋๋object
๊ฐ ๋ ๊ฒ์ด๋ค.- ๊ฐ์ฒด์ ํ์
์คํฌ๋ฆฝํธ์ ๋ํ๊ธฐ ์๊ณ ๋ฆฌ์ฆ์ ๊ฐ ์์๋ฅผ
let
์ผ๋ก ํ ๋นํ ๊ฒ์ฒ๋ผ ๋ค๋ฃฌ๋ค.- ๊ทธ๋์
v
์ ํ์ ์{x: number}
๊ฐ ๋๋ค. - ์ ์ฝ๋๋ฅผ ํ์
์คํฌ๋ฆฝํธ์์ ๊ตฌ๋ํ๋ฉด
v.x = 3;
์ ์ ์ธํ ๋๋จธ์ง ๊ตฌ๋ฌธ์ ๋ชจ๋ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
- ๊ทธ๋์
- ํ์
์คํฌ๋ฆฝํธ๋ ๋ช
ํ์ฑ๊ณผ ์ ์ฐ์ฑ ์ฌ์ด์ ๊ท ํ์ ์ ์งํ๋ ค๊ณ ํ๋ค.
- ์ค๋ฅ๋ฅผ ์ก๊ธฐ ์ํด์๋ ์ถฉ๋ถํ ๊ตฌ์ฒด์ ์ผ๋ก ํ์ ์ ์ถ๋ก ํด์ผ ํ์ง๋ง, ์๋ชป๋ ์ถ๋ก ์ ํ ์ ๋๋ก ๊ตฌ์ฒด์ ์ผ๋ก ์ํํ์ง๋ ์๋๋ค.
# (3) ํ์ ์คํฌ๋ฆฝํธ์ ๊ธฐ๋ณธ ๋์์ ์ฌ์ ์ํ๋ ๋ฐฉ๋ฒ
# โญ๏ธ ๋ช ์์ ํ์ ๊ตฌ๋ฌธ์ ์ ๊ณต
const v: { x: 1 | 3 | 5 } = {
x: 1,
}; // ํ์
์ด { x: 1 | 3 | 5; }
# โญ๏ธ ํ์ ์ฒด์ปค์ ์ถ๊ฐ์ ์ธ ๋ฌธ๋งฅ ์ ๊ณต
- ์๋ฅผ ๋ค์ด, ํจ์์ ๋งค๊ฐ๋ณ์๋ก ๊ฐ์ ์ ๋ฌํ๋ ๊ณผ์
# โญ๏ธ const
๋จ์ธ๋ฌธ ์ฌ์ฉ
const v1 = {
x: 1,
y: 2,
}; // ํ์
์ { x: number; y: number; }
const v2 = {
x: 1 as const,
y: 2,
}; // ํ์
์ { x:1; y: number; }
const v3 = {
x: 1,
y: 2,
} as const; // ํ์
์ { readonly x: 1; readonly y: 2; }
- ๊ฐ ๋ค์
as const
๋ฅผ ์์ฑํ๋ฉด, ํ์ ์คํฌ๋ฆฝํธ๋ ์ต๋ํ ์ข์ ํ์ ์ผ๋ก ์ถ๋ก ํ๋ค. - ์ด ๊ธฐ๋ฒ์ ๊ฐ์ฒด ๋ฟ๋ง ์๋๋ผ ๋ฐฐ์ด์์๋ ์ ์ฉํ ์ ์๋ค.
- ๋ํ๊ธฐ๋ก ์ธํด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค๊ณ ์๊ฐ๋๋ฉด, ๋ช
์์ ํ์
๊ตฌ๋ฌธ ๋๋
const
๋จ์ธ๋ฌธ์ ์ถ๊ฐํ๋ ๊ฒ์ ๊ณ ๋ คํด์ผ ํ๋ค.
# Item22. ํ์ ์ขํ๊ธฐ
# (1) ํ์ ์ขํ๋ ๋ฐฉ๋ฒ
- ํ์ ๋ํ๊ธฐ์ ๋ฐ๋๋ก ํ์ ์ขํ๊ธฐ๋ ๋์ ํ์ ์ผ๋ก๋ถํฐ ์ข์ ํ์ ์ผ๋ก ์งํํ๋ ๊ณผ์ ์ ๋งํ๋ค.
- ๊ฐ์ฅ ์ผ๋ฐ์ ์ธ ์์๋
null
์ฒดํฌ์ด๋ค.
const el = document.getElementById('foo'); // ํ์
์ด HTMLElement | null;
if (el) {
el // ํ์
์ด HTMLElement
el.innerHTML = 'Party Time'.blink();
} else {
el // ํ์
์ด null
alert('No element #foo!');
}
- ์์ ๊ฐ์ ์กฐ๊ฑด ๋ถ๊ธฐ๋ฌธ์ ํตํด์ ํ์
์ขํ๊ธฐ๋ฅผ ์ ํด๋ผ ์ ์๋ค.
- ํ์ง๋ง ํ์ ๋ณ์นญ์ด ์กด์ฌํ๋ค๋ฉด ๊ทธ๋ฌ์ง ๋ชปํ ์ ์๋ค. (์ถํ Item24 ์์ ์์ธํ ์งํ)
- ์ด์ธ์๋ ํ์ ์ขํ๋ ๋ฐฉ๋ฒ์ด ๋ค์ํ๊ฒ ์กด์ฌํ๋ค.
// ํ์
์ขํ๋ ๋ฐฉ๋ฒ(1) - ๋ถ๊ธฐ๋ฌธ์์ ์์ธ๋ฅผ ๋์ง๊ฑฐ๋ ํจ์๋ฅผ ๋ฐํ
const el = document.getElementById('foo'); // ํ์
์ด HTMLElement | null;
if (!el) throw new Error('Unable to find #foo')!
el; // ์ด์ ํ์
์ HTMLElement
el.innerHTML = 'Party Time'.blink();
// ํ์
์ขํ๋ ๋ฐฉ๋ฒ(2) - instanceof ์ฌ์ฉ
function contains(text: string, search: string | RegExp) {
if (search instanceof RegExp) {
search // ํ์
์ด RegExp
return !!search.exec(text);
}
search // ํ์
์ด string
return text.includes(search);
}
// ํ์
์ขํ๋ ๋ฐฉ๋ฒ(3) - ์์ฑ ์ฒดํฌ
interface A {
a: number;
}
interface B {
b: number;
}
function pickAB(ab: A | B) {
if ('a' in ab) {
ab // ํ์
์ด A
} else {
ab // ํ์
์ด B
}
ab // ํ์
์ด A | B
}
// ํ์
์ขํ๋ ๋ฐฉ๋ฒ(4) - Array.isArray ๊ฐ์ ์ผ๋ถ ๋ด์ฅ ํจ์๋ก๋ ํ์
์ ์ขํ ์ ์์
function contains(text: string, terms: string | string[]) {
const termList = Array.isArray(terms) ? terms : [terms];
termList // ํ์
์ด string[]
// ...
}
# โ ๏ธ ์ฃ๋ถ๋ฆฌ ํ์ ์ ์ขํ๋ค๊ฐ ์ค๋ฅ๋ฅผ ๋ฒํ๋ ๊ฒฝ์ฐ๋ฅผ ํผํ์!
- ์๋ฐ์คํฌ๋ฆฝํธ์์
typeof null
์"object"
์ด๋ฏ๋ก ์๋์ ๊ฐ์ ์ฝ๋๋ก๋null
์ฒดํฌ๋ฅผ ํ ์ ์๋ค.
const el = document.getElementById('foo'); // ํ์
์ด HTMLElement | null
if (typeof el === 'object') {
el; // ํ์
์ด HTMLElement | null
}
- ๋น ๋ฌธ์์ด
''
๊ณผ0
๋ชจ๋false
๊ฐ ๋๋ฏ๋ก, ํ์ ์ ์ ํ ์ขํ์ง์ง ์์๊ณx
๋ ์ฌ์ ํ ๋ธ๋ก ๋ด์์string
๋๋number
๊ฐ ๋๋ค.
function foo(x?: number | string | null) {
if (!x) {
x; // ํ์
์ด string | number | null | undefined;
}
}
# (2) ํ๊ทธ๋ ์ ๋์จ(tagged union) (๊ตฌ๋ณ๋ ์ ๋์จ(discriminated union))
interface UploadEvent {
type: 'upload';
filename: string;
contents: string;
}
interface DownloadEvent {
type: 'download';
filename: string;
}
type AppEvent = UploadEvent | DownloadEvent;
function handleEvent(e: AppEvent) {
switch (e.type) {
case 'download':
e // ํ์
์ด DownloadEvent
break;
case 'upload':
e // ํ์
์ด UploadEvent
break;
}
}
# (3) ์ฌ์ฉ์ ์ ์ ํ์ ๊ฐ๋
function isInputElement(el: HTMLElement): el is HTMLInputElement {
return 'value' in el;
}
function getElementContent(el: HTMLElement) {
if (isInputElement(el)) {
el; // ํ์
์ด HTMLInputElement
return el.value;
}
el; // ํ์
์ด HTMLElement
return el.textContent;
}
# (4) ํ์ ๊ฐ๋๋ฅผ ์ด์ฉํ ๋ฐฐ์ด๊ณผ ๊ฐ์ฒด์์์ ํ์ ์ขํ๊ธฐ
- ๋ฐฐ์ด์์ ์ด๋ค ํ์์ ์ํํ ๋
undefined
๊ฐ ๋ ์ ์๋ ํ์ ์ ์ฌ์ฉํ ์ ์๋ค.
const jackson5 = ['Jackie', 'Tito', 'Jermaine', 'Marlon', 'Michael'];
const members = ['Janet', 'Michael'].map(
who => jackson5.find(n => n === who)
); // ํ์
์ด (string | undefined)[]
filter
ํจ์๋ฅผ ์ฌ์ฉํดundefined
๋ฅผ ๊ฑธ๋ฌ ๋ด๋ ค๊ณ ํด๋ ์ ๋์ํ์ง ์๋๋ค.
const members = ['Janet', 'Michael'].map(
who => jackson5.find(n => n === who)
).filter(who => who !== undefined); // ํ์
์ด (string | undefined)[]
- ์ด๋ด ๋ ํ์ ๊ฐ๋๋ฅผ ์ฌ์ฉํ๋ฉด ํ์ ์ ์ขํ ์ ์๋ค.
function isDefined<T>(x: T | undefined): x is T {
return x !== undefined;
}
const members = ['Janet', 'Michael'].map(
who => jackson5.find(n => n === who)
).filter(isDefined); // ํ์
์ด string[]
# Item23. ํ๊บผ๋ฒ์ ๊ฐ์ฒด ์์ฑํ๊ธฐ
- ๊ฐ์ฒด๋ฅผ ์์ฑํ ๋๋ ์์ฑ์ ํ๋์ฉ ์ถ๊ฐํ๊ธฐ๋ณด๋ค๋ ์ฌ๋ฌ ์์ฑ์ ํฌํจํด์ ํ๊บผ๋ฒ์ ์์ฑํด์ผ ํ์ ์ถ๋ก ์ ์ ๋ฆฌํ๋ค.
const pt = {};
pt.x = 3; // ~ '{}' ํ์์ 'x' ์์ฑ์ด ์์ต๋๋ค.
pt.y = 4; // ~ '{}' ํ์์ 'y' ์์ฑ์ด ์์ต๋๋ค.
interface Point {
x: number;
y: number;
}
// ๋ฌผ๋ก ์๋์ ๊ฐ์ ๊ฒฝ์ฐ ํ์
๋จ์ธ๋ฌธ์ ์ด์ฉํด const pt = {} as Point;๋ก ์์ฑํด์ ํด๊ฒฐ์ ํ ์ ์๋ค.
const pt: Point = {}; // ~~ '{}' ํ์์ 'Point' ํ์์ x, y ์์ฑ์ด ์์ต๋๋ค.
pt.x = 3;
pt.y = 4;
const pt = {
x: 3,
y: 4,
}; // ์ ์
- ์์ ๊ฐ์ฒด๋ค์ ์กฐํฉํด์ ํฐ ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ผ ํ๋ ๊ฒฝ์ฐ์๋ ์ฌ๋ฌ ๋จ๊ณ๋ฅผ ๊ฑฐ์น์ง ์๊ณ ๊ฐ์ฒด ์ ๊ฐ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํด์ ํฐ ๊ฐ์ฒด๋ฅผ ํ๊บผ๋ฒ์ ๋ง๋ค์ด๋ด๋ ๊ฒ์ด ์ข๋ค.
- ๊ฐ์ฒด ์ ๊ฐ ์ฐ์ฐ์๋ฅผ ์ฌ์ฉํ๋ฉด ํ์ ๊ฑฑ์ ์์ด ํ๋ ๋จ์๋ก ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๋ค.
- ์ด ๋ฐฉ๋ฒ์ ๊ฐ๋จํ ๊ฐ์ฒด๋ฅผ ๋ง๋ค๊ธฐ ์ํด ์ฐํํ๊ธฐ๋ ํ์ง๋ง, ๊ฐ์ฒด์ ์์ฑ์ ์ถ๊ฐํ๊ณ ํ์ ์คํฌ๋ฆฝํธ๊ฐ ์๋ก์ด ํ์ ์ ์ถ๋ก ํ ์ ์๊ฒ ํด ์ ์ฉํ๋ค.
- ํ์
์ ์์ ํ ๋ฐฉ์์ผ๋ก ์กฐ๊ฑด๋ถ ์์ฑ์ ์ถ๊ฐํ๋ ค๋ฉด, ์์ฑ์ ์ถ๊ฐํ์ง ์๋
null
๋๋{}
์ผ๋ก ๊ฐ์ฒด ์ ๊ฐ๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
declare let hasMiddle: boolean;
const firstLast = {first: 'Harry', last: 'Truman'};
const president = {...firstLast, ...(hasMiddle ? {middle: 'S'} : {})};
- ์ ์ฝ๋๋ฅผ ํธ์ง๊ธฐ์์
president
์ ๋ง์ฐ์ค๋ฅผ ์ฌ๋ฆฌ๋ฉด ์๋์ ๊ฐ์ด ํ์ ์ด ์ถ๋ก ๋๋ค.
const persident: {
middle?: string;
first: string;
last: string;
}
- ์ ๊ฐ ์ฐ์ฐ์๋ก ํ๊บผ๋ฒ์ ์ฌ๋ฌ ์์ฑ์ ์ถ๊ฐํ ์๋ ์๋ค.
declare let hasDates: boolean;
const nameTitle = {name: 'Khufu', title: 'Pharaoh'};
const pharaoh = {
...nameTitle,
...(hasDates ? {start: -2589, end: -2566} : {})
};
pharaoh.start // ํ์
์ค๋ฅ
- ์ ์ฝ๋๋ฅผ ํธ์ง๊ธฐ์์
pharaoh
์ ๋ง์ฐ์ค๋ฅผ ์ฌ๋ฆฌ๋ฉด ์๋์ ๊ฐ์ด ํ์ ์ด ์ถ๋ก ๋๋ค.
const pharaoh: {
start: number;
end: number;
name: string;
title: string;
} | {
name: string;
title: string;
}
- ๋ฌด์ธ๊ฐ ์์น ์์ ํ์
ํํ๋ก ์ถ๋ก ์ด ๋์๋ค.
- ์ด๋ฌํ ๊ฒฝ์ฐ์๋ ์ ๋์จ์ ์ฌ์ฉํ๋ ๊ฒ ๊ฐ๋ฅํ ๊ฐ์ ์งํฉ์ ๋ ์ ํํ ํํํ ์ ์๋ค.
- ํ์ง๋ง ์ ๋์จ ๋ณด๋ค๋ ์ ํ์ ํ๋๊ฐ ๋ค๋ฃจ๊ธฐ์๋ ๋ ์ฌ์ธ ์ ์๋ค.
- ์ ํ์ ํ๋ ๋ฐฉ์์ผ๋ก ํํํ๋ ค๋ฉด ๋ค์์ฒ๋ผ ํฌํผ ํจ์๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
function addOptional<T extends object, U extends object>(
a: T, b: U | null
): T & Partial<U> {
return {...a, ...b};
}
const pharaoh = addOptional(
nameTitle,
(hasDates ? {start: -2589, end: -2566} : null
);
pharaoh.start // ์ ์, ํ์
์ด number | undefined