# ๐ Item11 ~ 15
# Item11. ์์ฌ ์์ฑ ์ฒดํฌ์ ํ๊ณ ์ธ์งํ๊ธฐ
- ๋ค์ ๋ ์์ ์ ์ฐจ์ด๋ฅผ ์์๋ณด์.
// example 1
interface Room {
numDoors: number;
ceilingHeightFt: number;
}
const r: Room = {
numDoors: 1,
ceilingHeightFt: 10,
elephant: 'present',
}
// example 2
interface Room {
numDoors: number;
ceilingHeightFt: number;
}
const obj = {
numDoors: 1,
ceilingHeightFt: 10,
elephant: 'present',
}
const r: Room = obj;
- example 1์์
r
์ ํ์ ์ฒด์ปค๊ฐ ํด๋น๋๋ ์์ฑ์ด ์๊ธฐ ๋๋ฌธ์ ์๋ฌ๋ฅผ ๋ฐ์ํ๋ค. - example 2์์
obj
ํ์ ์{ numDoors: number; ceilingHeightFt: number; elephant: string }
์ผ๋ก ์ถ๋ก ๋์ดobj
ํ์ ์Room
ํ์ ์ ๋ถ๋ถ ์งํฉ์ ํฌํจํ๋ฏ๋ก,Room
์ ํ ๋น ๊ฐ๋ฅํ๋ฉฐ ํ์ ์ฒด์ปค๋ ํต๊ณผํ๋ค. - ์ฒซ ๋ฒ์งธ ์์์ ๊ฒฝ์ฐ, ๊ตฌ์กฐ์ ํ์ ์์คํ ์์ ๋ฐ์ํ ์ ์๋ ์ค์ํ ์ค๋ฅ ์ค ํ๋์ธ '์์ฌ ์์ฑ ์ฒดํฌ' ๊ณผ์ ์ด ์ํ๋์ด์ ์ค๋ฅ๋ฅผ ๋ฐ์ํ๋ค.
- ์์ฌ ์์ฑ ์ฒดํฌ๊ฐ ํ ๋น ๊ฐ๋ฅ๊ฒ์ฌ์๋ ๋ณ๋์ ๊ณผ์ ์ด๋ผ๋ ๊ฒ์ ์์์ผ ํ์ ์คํฌ๋ฆฝํธ ํ์ ์์คํ ์ ๋ํ ๊ฐ๋ ์ ์ ํํ ์ก์ ์ ์๋ค.
interface Options {
title: string;
darkMode?: boolean;
}
function createWindow(options: Options) {
if (options.darkMode) {
setDarkMode();
}
}
createWindow({
title: 'Spider Solitaire',
darkmode: true,
})
- ์ ์ฝ๋๋ฅผ ์คํํ๋ฉด ๋ฐํ์์ ์ด๋ค ์ข
๋ฅ์ ์ค๋ฅ๋ ๋ฐ์ํ์ง ์๋๋ค.
- ๊ทธ๋ฌ๋ ํ์ ์คํฌ๋ฆฝํธ๊ฐ "๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ์๋ ค์ง ์์ฑ๋ง ์ง์ ํ ์ ์์ง๋ง 'Options' ํ์์ 'darkmode'์ด(๊ฐ) ์์ต๋๋ค. 'darkMode'์(๋ฅผ) ์ฐ๋ ค๊ณ ํ์ต๋๊น?"์ ๊ฐ์ ์ค๋ฅ ๋ฉ์์ง์ฒ๋ผ ์๋ํ ๋๋ก ๋์ํ์ง ์์ ์ ์๋ค.
Options
ํ์ ์ ๋ฒ์๊ฐ ๋งค์ฐ ๋์ด ์์ํ ๊ตฌ์กฐ์ ํ์ ์ฒด์ปค๋ ์ด๋ฌํ ์ข ๋ฅ์ ์ค๋ฅ๋ฅผ ์ฐพ์๋ด์ง ๋ชปํ๋ค.
// ๋๋ค string ํ์
์ธ title ์์ฑ์ ๊ฐ์ง๊ณ ์์ด์ ํ ๋น๋ฌธ์ ์ ์(๋ ๊ฐ์ง ๋ชจ๋ ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ด ์๋๋ฏ๋ก ์์ฌ ์์ฑ ์ฒดํฌ๊ฐ ๋์ง ์์)
const o1: Options = document; // ์ ์
const o2: Options = new HTMLAnchorElement; // ์ ์
- ์์ฌ ์์ฑ ์ฒดํฌ๋ฅผ ์ด์ฉํ๋ฉด ๊ธฐ๋ณธ์ ์ผ๋ก ํ์ ์์คํ ์ ๊ตฌ์กฐ์ ๋ณธ์ง์ ํด์น์ง ์์ผ๋ฉด์๋ ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ์ ์ ์๋ ์์ฑ์ ํ์ฉํ์ง ์์์ผ๋ก์จ ์ค๋ฅ๋ฅผ ๋ง์ ์ ์๋ค.
// ์๋ ๊ตฌ๋ฌธ์ ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ด๋ฏ๋ก ์์ฌ ์์ฑ ์ฒดํฌ๊ฐ ๋๋ค.
const o3: Options = { darkmode: true, title: 'Ski Free' }; // ~~~ 'Options' ํ์์ 'darkmode'์ด(๊ฐ) ์์ต๋๋ค.
// ํ์
๋จ์ธ๋ฌธ์ ์ฌ์ฉํ๊ฒ ๋๋ฉด ์์ฌ ์์ฑ ์ฒดํฌ๊ฐ ์ ์ฉ๋์ง ์์ผ๋ฏ๋ก ๊ฐ๊ธ์ ์ด๋ฉด ์ ์ธ๋ฌธ์ ์ด์ฉํด์ผ ํ๋ค.
const o4 = { darkmode: true, title: 'Ski Free' } as Options; // ์ ์
- ๋ง์ฝ ์์ฌ ์์ฑ ์ฒดํฌ๋ฅผ ์์น ์๋๋ค๋ฉด, ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๋ฅผ ์ฌ์ฉํด์ ํ์ ์คํฌ๋ฆฝํธ๊ฐ ์ถ๊ฐ์ ์ธ ์์ฑ์ ์์ํ๋๋ก ํ ์ ์๋ค.
interface Options {
[otherOptions: string]: unknown;
darkMode?: boolean;
}
const o5: Options = { darkmode: true }; // ์ ์
# Item12. ํจ์ ํํ์์ ํ์ ์ ์ฉํ๊ธฐ
# โ ํจ์ ๋ฌธ์ฅ๊ณผ ํจ์ ํํ์
- ํํ์(expressions)
- ๊ฐ ํ๋๋ก ๊ท๊ฒฐ๋๋ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋ ์กฐ๊ฐ
- ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋ ์ค ๊ฐ์ด ๋ค์ด๊ฐ๋ ๊ณณ์ด๋ฉด ์ด๋์๋ ๋ฃ์ ์ ์๋ค.
- ๋ฌธ์ฅ(statements)
- ์๋ฐ์คํฌ๋ฆฝํธ์์ ๋ฌธ์ฅ์ ๊ฐ์ด ๋ค์ด์์ผ ํ ๊ณณ์ ๋ค์ด๊ฐ ์ ์๋ค.
- ์ด ๋ค์ ํจ์์ ์ธ์๋ก๋, ๋์ ์ฐ์ฐ์ ๊ฐ์ผ๋ก๋, ์ฐ์ฐ์์ ํผ์ฐ์ฐ์๋ก๋ ์ฌ์ฉ๋ ์ ์๋ค.
function rollDice1(sides) { ... } // ํจ์ ๋ฌธ์ฅ
const rollDice2 = function(sides) { ... } // ํจ์ ํํ์
const rollDice3 = (sides) => { ... } // ํจ์ ํํ์
- ํจ์ ๋ฌธ์ฅ๊ณผ ํจ์ ํํ์์ ์ฐจ์ด
- 'ํจ์ ๋ฌธ์ฅ'์ผ๋ก ์ ์๋ ํจ์๋ ํด๋น ํจ์๋ฅผ ํธ์ถํ๋ ์ฝ๋๊ฐ ํจ์๋ฅผ ์ ์ํ๋ ๋ฌธ์ฅ๋ณด๋ค ์์ ์๊ฑด ๋ค์ ์๊ฑด ์ ํจ๋ด์(ํจ์ ์ ํจ๋ฒ์)๋ง ๊ฐ์ผ๋ฉด ๋ฌธ์ ์๋ค.
- ํ์ง๋ง 'ํจ์ ํํ์'์ผ๋ก ์ ์๋ ํจ์๋ ํจ์๋ฅผ ์ ์ํ๋ ๋ฌธ์ฅ๋ณด๋ค ๋ค์ ์์ด์ผ๋ง ํ๋ค.
foo(); // ์ ์ ๋์
function foo() {
alert('call foo');
}
bar(); // ๋น์ ์ ๋์
const bar = function() {
alert('call bar');
}
๐ Reference
https://velog.io/@fromzoo/%ED%91%9C%ED%98%84%EC%8B%9DExpression%EA%B3%BC-%EB%AC%B8%EC%9E%A5Statement
https://dimdim.tistory.com/entry/%EC%9E%90%EB%B0%94%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8-%ED%95%A8%EC%88%98%EB%AC%B8%EC%9E%A5-%EA%B3%BC-%ED%95%A8%EC%88%98%ED%91%9C%ED%98%84%EC%8B%9D%EC%9D%98-%EC%B0%A8%EC%9D%B4
- ํ์
์คํฌ๋ฆฝํธ์์๋ ํจ์ ํํ์์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
- ํจ์์ ๋งค๊ฐ๋ณ์๋ถํฐ ๋ฐํ๊ฐ๊น์ง ์ ์ฒด๋ฅผ ํจ์ ํ์ ์ผ๋ก ์ ์ธํ์ฌ ํจ์ ํํ์์ ์ฌ์ฌ์ฉํ ์ ์๋ค๋ ์ฅ์ ์ด ์๊ธฐ ๋๋ฌธ์ด๋ค.
- ๊ทธ๋ฆฌ๊ณ ๋ถํ์ํ ์ฝ๋์ ๋ฐ๋ณต์ ์ค์ผ ์๋ ์๋ค.
- ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ ๊ณตํต ํจ์ ์๊ทธ๋์ฒ๋ฅผ ํ์
์ผ๋ก ์ ๊ณตํ๊ธฐ๋ ํ๋ค.
- ์ง์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๋ง๋ ๋ค๋ฉด, ๊ณตํต ์ฝ๋ฐฑ ํจ์๋ฅผ ์ํ ํ์ ์ ์ธ์ ์ ๊ณตํ๋ ๊ฒ์ด ์ข๋ค.
- ์์) ์น ๋ธ๋ผ์ฐ์ ์์
fetch
ํจ์
declare function fetch(
input: RequestInfo, init?: RequestInit
): Promise<Response>;
async function checkedFetch(input: RequestInfo, init?: RequestInit) {
const response = await fetch(input, init);
if (!response.ok) {
// ๋น๋๊ธฐ ํจ์ ๋ด์์ ๊ฑฐ์ ๋ ํ๋ก๋ฏธ์ค๋ก ๋ณํ
throw new Error(`Request failed: ${response.status}`);
}
return response;
}
// ์ ์ฝ๋์์ ๋ ๊ฐ๊ฒฐํด์ง ๋ฒ์
// 1. ํจ์ ๋ฌธ์์ ํจ์ ํํ์์ผ๋ก ๊ต์ฒด
// 2. ํจ์ ์ ์ฒด์ ํ์
(typeof fetch)์ ์ ์ฉ => ํ์
์คํฌ๋ฆฝํธ๊ฐ input๊ณผ init์ ํ์
์ ์ถ๋ก ํ ์ ์๊ฒ ํด ์ค
const checkedFetch: typeof fetch = async (input, init) => {
const response = await fetch(input, init);
if (!response.ok) {
// ๋น๋๊ธฐ ํจ์ ๋ด์์ ๊ฑฐ์ ๋ ํ๋ก๋ฏธ์ค๋ก ๋ณํ
throw new Error(`Request failed: ${response.status}`);
}
return response;
}
- ํจ์์ ๋งค๊ฐ๋ณ์์ ํ์
์ ์ธ์ ํ๋ ๊ฒ๋ณด๋ค ํจ์ ํํ์ ์ ์ฒด ํ์
์ ์ ์ํ๋ ๊ฒ์ด ์ฝ๋๋ ๊ฐ๊ฒฐํ๊ณ ์์ ํ๋ค.
- ๋ค๋ฅธ ํจ์์ ์๊ทธ๋์ฒ์ ๋์ผํ ํ์ ์ ๊ฐ์ง๋ ์ ํจ์๋ฅผ ์์ฑํ๊ฑฐ๋, ๋์ผํ ํ์ ์๊ทธ๋์ฒ๋ฅผ ๊ฐ์ง๋ ์ฌ๋ฌ ๊ฐ์ ํจ์๋ฅผ ์์ฑํ ๋๋ ๋งค๊ฐ๋ณ์์ ํ์ ๊ณผ ๋ณํ ํ์ ์ ๋ฐ๋ณตํด์ ์์ฑํ์ง ๋ง๊ณ ํจ์ ์ ์ฒด์ ํ์ ์ ์ธ์ ์ ์ฉํด์ผ ํ๋ค.
# Item13. ํ์ ๊ณผ ์ธํฐํ์ด์ค์ ์ฐจ์ด์ ์๊ธฐ
# (1) ๊ณตํต์
- ๋ช ๋ช ๋ ํ์ ์ผ ๋๋ ํ์ , ์ธํฐํ์ด์ค ๋ชจ๋ ์ถ๊ฐ ์์ฑ๊ณผ ํจ๊ป ํ ๋นํ๋ฉด ์๋ ์ฝ๋์ ๊ฐ์ด ๋์ผํ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
type TUser = {
name: string;
age: number;
}
interface IUser {
name: string;
age: number;
}
const wally: TUser = {
name: 'wally',
age: 28,
zipCode: 12345, // ํ์ 'TUser' ํ์์ ํ ๋นํ ์ ์๋ค. ๊ฐ์ฒด ๋ฆฌํฐ๋ด์ ์๋ ค์ง ์์ฑ๋ง ์ง์ ํ ์ ์์ผ๋ฉฐ 'TUser' ํ์์ 'zipCode'์ด(๊ฐ) ์๋ค.
}
- ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๋ ์ธํฐํ์ด์ค, ํ์ ๋ชจ๋ ์ฌ์ฉํ ์ ์๋ค.
type TDict = { [key: string] = string };
interface IDict {
[key: string]: string;
}
- ํจ์ ํ์ ๋ ์ธํฐํ์ด์ค, ํ์ ๋ชจ๋ ์ ์ํ ์ ์๋ค.
type TFn = (x: number) => string;
interface IFn {
(x: number): string;
}
const toStrT: TFn = x => '' + x; // ์ ์
const toStrI: IFn = x => '' + x; // ์ ์
ํ์ ๋ณ์นญ๊ณผ ์ธํฐํ์ด์ค ๋ชจ๋ ์ ๋ค๋ฆญ์ด ๊ฐ๋ฅํ๋ค.
์ธํฐํ์ด์ค๋ ํ์ ์, ํ์ ์ ์ธํฐํ์ด์ค๋ฅผ ํ์ฅํ ์ ์๋ค.
- ๋จ, ์ฃผ์ํ ์ ์ ์ธํฐํ์ด์ค๋ ์ ๋์จ ํ์ ๊ฐ์ ๋ณต์กํ ํ์ ์ ํ์ฅํ์ง๋ ๋ชปํ๋ค.
- ๋ณต์กํ ํ์
์ ํ์ฅํ๊ณ ์ถ๋ค๋ฉด ํ์
๊ณผ
&
๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
interface IStateWithPop extends TState {
population: number;
}
type TStateWithPop = IState & { population: number };
- ํด๋์ค๋ฅผ ๊ตฌํ(
implements
)ํ ๋๋ ํ์ ๊ณผ ์ธํฐํ์ด์ค ๋ ๋ค ์ฌ์ฉํ ์ ์๋ค.
# (2) ์ฐจ์ด์
- ์ ๋์จ ํ์ ์ ์์ง๋ง ์ ๋์จ ์ธํฐํ์ด์ค๋ผ๋ ๊ฐ๋ ์ ์๋ค.
- ์ธํฐํ์ด์ค๋ ํ์
์ ํ์ฅํ ์ ์์ง๋ง, ์ ๋์จ์ ํ ์ ์๋ค.
- ๊ทธ๋ฐ๋ฐ ์ ๋์จ ํ์ ์ ํ์ฅํ๋ ๊ฒ ํ์ํ ๋๊ฐ ์๋ค.
type Input = { ... };
type Output = { ... };
interface VariableMap {
[name: string]: Input | Output;
}
- ๋๋ ์ ๋์จ ํ์
์
name
์์ฑ์ ๋ถ์ธ ํ์ ์ ๋ง๋ค ์๋ ์๋ค.
// ์ด ํ์
์ ์ธํฐํ์ด์ค๋ก ํํํ ์ ์๋ค.
// type ํค์๋๋ ์ ๋์จ์ด ๋ ์ ์๊ณ , ๋งคํ๋ ํ์
๋๋ ์กฐ๊ฑด๋ถ ํ์
๊ฐ์ ๊ณ ๊ธ ๊ธฐ๋ฅ์ ํ์ฉ๋๊ธฐ๋ ํ๋ค.
type NamedVariable = (Input | Output) & { name: string };
- ํํ๊ณผ ๋ฐฐ์ด ํ์
๋
type
ํค์๋๋ฅผ ์ด์ฉํด ๋ ๊ฐ๊ฒฐํ๊ฒ ํํํ ์ ์๋ค.- ์ธํฐํ์ด์ค๋ก๋ ํํ๊ณผ ๋น์ทํ๊ฒ ๊ตฌํํ ์ ์์ผ๋ ํํ์์ ์ฌ์ฉํ ์ ์๋
concat
๊ฐ์ ๋ฉ์๋๋ค์ ์ฌ์ฉํ ์ ์๋ค.
- ์ธํฐํ์ด์ค๋ก๋ ํํ๊ณผ ๋น์ทํ๊ฒ ๊ตฌํํ ์ ์์ผ๋ ํํ์์ ์ฌ์ฉํ ์ ์๋
type Pair = [number, number];
type StringList = string[];
type NamedNums = [string, ...number[]];
- ์ธํฐํ์ด์ค๋ ํ์
์ ์๋ '๋ณด๊ฐ(augment)' ์ด ๊ฐ๋ฅํ๋ค.
- ์๋ ์ฝ๋์ ๊ฐ์ด '์ ์ธ ๋ณํฉ(declaration merging)'์ ์ด์ฉํด์ ์ธํฐํ์ด์ค๋ฅผ ๋ณด๊ฐํ ์ ์๋ค.
- ํ์ ์ ์ธ ํ์ผ์ ์์ฑํ ๋๋ ์ ์ธ ๋ณํฉ์ ์ง์ํ๊ธฐ ์ํด ๋ฐ๋์ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํด์ผ ํ๋ฉฐ ํ์ค์ ๋ฐ๋ผ์ผ ํ๋ค.
- ํ์ ์ ์ธ์๋ ์ฌ์ฉ์๊ฐ ์ฑ์์ผ ํ๋ ๋นํ์ด ์์ ์ ์๋๋ฐ, ๋ฐ๋ก ์ด ์ ์ธ ๋ณํฉ์ด ๊ทธ๋ ๋ค.
interface IState {
name: string;
captial: string;
}
interface IState {
population: number;
}
const wyoming: IState {
name: 'Wyoming',
captial: 'Cheyenne',
population: 500000,
}; // ์ ์
- ๋ณํฉ์ ์ ์ธ๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์ผ๋ฐ์ ์ธ ์ฝ๋์์๋ ์ง์๋๋ฏ๋ก ์ธ์ ๋ณํฉ์ด ๊ฐ๋ฅํ์ง ์๊ณ ์์ด์ผ ํ๋ค.
- ํ์ ์ ๊ธฐ์กด ํ์ ์ ์ถ๊ฐ์ ์ธ ๋ณด๊ฐ์ด ์๋ ๊ฒฝ์ฐ์๋ง ์ฌ์ฉํด์ผ ํ๋ค.
# (3) ํ์ ๊ณผ ์ธํฐํ์ด์ค ์ค ์ด๋ค ๊ฒ์ ์จ์ผํ ๊น
- ๋ณต์กํ ํ์ ์ด๋ผ๋ฉด ๊ณ ๋ฏผํ ๊ฒ๋ ์์ด ํ์ ๋ณ์นญ์ ์ฌ์ฉํ๋ฉด ๋๋ค.
- ํ์
๊ณผ ์ธํฐํ์ด์ค, ๋ ๊ฐ์ง ๋ฐฉ๋ฒ์ผ๋ก ๋ชจ๋ ํํํ ์ ์๋ ๊ฐ๋จํ ๊ฐ์ฒด ํ์
์ด๋ผ๋ฉด ์ผ๊ด์ฑ๊ณผ ๋ณด๊ฐ์ ๊ด์ ์์ ๊ณ ๋ คํด ๋ด์ผ ํ๋ค.
- ์ผ๊ด๋๊ฒ ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ ์ฝ๋๋ฒ ์ด์ค์์ ์์ ํ๊ณ ์๋ค๋ฉด ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๊ณ , ์ผ๊ด๋๊ฒ ํ์ ์ ์ฌ์ฉ ์ค์ด๋ผ๋ฉด ํ์ ์ ์ฌ์ฉํ๋ฉด ๋๋ค.
- ์ด๋ค API์ ๋ํ ํ์
์ ์ธ์ ์์ฑํด์ผ ํ๋ค๋ฉด ์ธํฐํ์ด์ค๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ์ข๋ค.
- API๊ฐ ๋ณ๊ฒฝ๋ ๋ ์ฌ์ฉ์๊ฐ ์ธํฐํ์ด์ค๋ฅผ ํตํด ์๋ก์ด ํ๋๋ฅผ ๋ณํฉํ ์ ์์ด ์ ์ฉํ๊ธฐ ๋๋ฌธ์ด๋ค.
# Item14. ํ์ ์ฐ์ฐ๊ณผ ์ ๋ค๋ฆญ ์ฌ์ฉ์ผ๋ก ๋ฐ๋ณต ์ค์ด๊ธฐ
- DRY(Don't Repeat Yourself) ์์น์ ํ์ ์๋ ์ต๋ํ ์ ์ฉํด์ผ ํ๋ค.
- ํ์
์ ์ด๋ฆ์ ๋ถ์ฌ์ ๋ฐ๋ณต์ ํผํด์ผ ํ๋ค.
extends
๋ฅผ ์ฌ์ฉํด์ ์ธํฐํ์ด์ค ํ๋์ ๋ฐ๋ณต์ ํผํด์ผ ํ๋ค.
# โญ๏ธ ์์1 - mapped type
// before
interface State {
userId: string;
pageTitle: string;
recentFiles: string[];
pageContents: string;
}
interface TopNavState {
userId: string;
pageTitle: string;
recentFiles: string[];
}
// 1) State ์ธ๋ฑ์ฑ
type TopNavState = {
userId: State['userId'];
pageTitle: State['pageTitle'];
recentFiles: State['recentFiles'];
}
// 2) mapped type ์ ์ฉ
type TopNavState = {
[k in 'userId' | 'pageTitle' | 'recentFiles']: State[k]
}
// 3) ์ ํธ๋ฆฌํฐ ํ์
์ธ Pick ์ ์ฉ
type TopNavState = Pick<State, 'userId' | 'pageTitle' | 'recentFiles'>;
# โญ๏ธ ์์2 - ํ๊ทธ๋ ์ ๋์จ
interface SaveAction {
type: 'save';
}
interface LoadAction {
type: 'load';
}
type Action = SaveAction | LoadAction;
type ActionType = 'save' | 'load'; // ํ์
์ ๋ฐ๋ณต!
// Action ์ ๋์จ ํ์
์ ์ธ๋ฑ์ฑ
type ActionType = Action['type']; // ํ์
์ "save" | "load"
# โญ๏ธ ์์3 - keyof
์ฐ์ฐ์ ์ฌ์ฉ
interface Options {
width: number;
height: number;
color: string;
label: string;
}
interface OptionsUpdate {
width?: number;
height?: number;
color?: string;
label?: string;
}
class UIWidget {
constructor(init: Options) { ... }
update(options: OptionsUpdate) { ... }
}
// ๋งคํ๋ ํ์
๊ณผ keyof๋ฅผ ์ฌ์ฉ
type OptionsKeys = keyof Options; // "width" | "height" | "color" | "label"
type OptionsUpdate = { [k in keyof Options]?: Options[k] };
// ์ ํธ๋ฆฌํฐ ํ์
์ธ Partial ์ ์ฉ
type OptionsUpdate = Partial<Options>;
# โญ๏ธ ์์4 - ๊ฐ์ ํํ์ ํด๋นํ๋ ํ์ ์ ์
- ๊ฐ์ผ๋ก๋ถํฐ ํ์
์ ๋ง๋ค์ด ๋ผ ๋๋ ์ ์ธ์ ์์์ ์ฃผ์ํด์ผ ํ๋ค.
- ํ์ ์ ์๋ฅผ ๋จผ์ ํ๊ณ ๊ฐ์ด ๊ทธ ํ์ ์ ํ ๋น ๊ฐ๋ฅํ๋ค๊ณ ์ ์ธํ๋ ๊ฒ์ด ์ข๋ค.
- ๊ทธ๋ ๊ฒ ํด์ผ ํ์ ์ด ๋ ๋ช ํํด์ง๊ณ , ์์ํ๊ธฐ ์ด๋ ค์ด ํ์ ๋ณ๋์ ๋ฐฉ์งํ ์ ์๋ค.
const INIT_OPTIONS = {
width: 640,
height: 480,
color: '#00FF00',
label: 'VGA',
};
type Options = typeof INIT_OPTIONS;
- ํจ์๋ ๋ฉ์๋์ ๋ฐํ ๊ฐ์ ๋ช
๋ช
๋ ํ์
๋ง๋๋ ๊ฒฝ์ฐ
- ์ด๋๋ ์กฐ๊ฑด๋ถ ํ์ ์ด ํ์ํ๋ ํ์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์๋ ์ผ๋ฐ์ ํจํด์ ์ ๋ค๋ฆญ ํ์ ์ด ์ ์๋์ด ์๋ค.
- ์ด๋ฐ ๊ฒฝ์ฐ ์ ํธ๋ฆฌํฐ ํ์
์ธ
ReturnType
์ ์ฌ์ฉํ๋ฉด ๋๋ค.
function getUserInfo(userId: string) {
// ์๋ต
return {
userId,
name,
age,
zipCode,
};
}
type UserInfo = ReturnType<typeof getUserInfo>;
typeof
๋ฅผ ์ ์ฉํ ๋๋ ์ ์ฉ ๋์์ด ๊ฐ์ธ์ง ํ์ ์ธ์ง ์ ํํ ์๊ณ , ๊ตฌ๋ถํด์ ์ฒ๋ฆฌํด์ผ ํ๋ค.
# โญ๏ธ ์์5 - ์ ๋ค๋ฆญ ํ์ ์ ํ
- ์ ๋ค๋ฆญ ํ์
์ ํ์
์ ์ํ ํจ์์ ๊ฐ๋ค.
- ํ์ ์ ๋ฐ๋ณตํ๋ ๋์ ์ ๋ค๋ฆญ ํ์ ์ ์ฌ์ฉํ์ฌ ํ์ ๋ค ๊ฐ์ ๋งคํ์ ํ๋ ๊ฒ์ด ์ข๋ค.
- ์ ๋ค๋ฆญ ํ์
์ ์ ํํ๋ ค๋ฉด
extends
ํค์๋๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
interface Name {
first: string;
last: string;
}
type DancingDuo<T extends Name> = [T, T];
const couple1: DancingDuo<Name> = [
{ name: 'Fred', last: 'Astaire' },
{ name: 'Ginger', last: 'Rogers' },
]; // ์ ์
// '{ first: string; }'์ Name์ ํ์ฅํ์ง ์๊ธฐ ๋๋ฌธ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
const couple2: DancingDuo<{first: string}> = [
{ first: 'Sonny' },
{ first: 'Cher' },
]; // 'Name' ํ์
์ ํ์ํ 'last' ์์ฑ์ด '{ first: string; }' ํ์
์ ์๋ค.
Pick
์ ์ด์ฉํด์๋ ๋์ผํ ๋ชจ์ต์ ๋ณผ ์ ์๋ค.
// Pick ๊ตฌํ ๋ชจ์ต
// K๋ ์ค์ ๋ก T์ ํค์ ๋ถ๋ถ ์งํฉ, ์ฆ keyof T๊ฐ ๋์ด์ผ ํ๋ค.
// ๋ํ ํ์
์ด ๊ฐ์ ์งํฉ์ด๋ผ๋ ๊ด์ ์์ ์๊ฐํ๋ฉด extends๋ฅผ 'ํ์ฅ'์ด ์๋๋ผ '๋ถ๋ถ ์งํฉ'์ด๋ผ๋ ๊ฒ์ผ๋ก ์ดํดํด์ผ ํ๋ค.
type Pick<T, K extends keyof T> = {
[k in K]: T[k]
};
type FirstLast = Pick<Name, 'first' | 'last'>; // ์ ์
type FirstMiddle = Pick<Name, 'first' | 'middle'>; // '"middle"' ํ์์ '"first" | "last"' ํ์์ ํ ๋นํ ์ ์๋ค.
# Item15. ๋์ ๋ฐ์ดํฐ์ ์ธ๋ฑ์ค ์๊ทธ๋์ฒ ์ฌ์ฉํ๊ธฐ
// ํ์
์คํฌ๋ฆฝํธ์์ ์ธ๋ฑ์ค ์๊ทธ๋์ฒ ์ฌ์ฉํ ์์
type Rocket = { [property: string]: string };
const rocket: Rocket = {
name: 'Falcon 9',
variant: 'v1.0',
thrust: '4,940 kN',
}; // ์ ์
- ์ธ๋ฑ์ค ์๊ทธ๋์ฒ์ ๊ฐ ์๋ฏธ
๋ถ๋ฅ | ์ค๋ช |
---|---|
ํค์ ์ด๋ฆ | ํค์ ์์น๋ง ํ์ํ๋ ์ฉ๋๋ก ํ์ ์ฒด์ปค์์๋ ์ฌ์ฉ ์ ํจ |
ํค์ ํ์ | string ์ด๋ number ๋๋ symbol ์ ์กฐํฉ์ด์ด์ผ ํ์ง๋ง, ๋ณดํต์ string ์ ์ฌ์ฉํจ |
๊ฐ์ ํ์ | ์ด๋ค ๊ฒ์ด๋ ๋ ์ ์์ |
- ๋์ ๋ฐ์ดํฐ์ ์ธ๋ฑ์ค ์๊ทธ๋์ฒ ์ฌ์ฉํ๋ ์ ํํ ๋ฐฉ๋ฒ
interface Rocket {
name: string;
variant: string;
thrust_kN: number;
}
const falconHeavy: Rocket = {
name: 'Falcon Heavy',
variant: 'v1',
thrust_kN: 15200
};
- ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๋ ๋์ ๋ฐ์ดํฐ๋ฅผ ํํํ ๋ ์ฌ์ฉํ๋ค.
- ์๋ฅผ ๋ค์ด CSV ํ์ผ์ฒ๋ผ ํค๋ ํ์ ์ด ์ด๋ฆ์ด ์๊ณ , ๋ฐ์ดํฐ ํ์ ์ด ์ด๋ฆ๊ณผ ๊ฐ์ผ๋ก ๋งคํํ๋ ๊ฐ์ฒด๋ก ๋ํ๋ด๊ณ ์ถ์ ๊ฒฝ์ฐ๋ค.
- ์ผ๋ฐ์ ์ธ ์ํฉ์์ ์ด ์ด๋ฆ์ด ๋ฌด์์ธ์ง ์๊ธฐ ์ด๋ ค์ธ ๋ ์๋์ ๊ฐ์ด ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
function parseCSV(input: string): { [columnName: string]: string }[] {
const lines = input.split('\n');
const [ header, ...rows ] = lines;
const headerColumns = header.split(',');
return rows.map(rowStr => {
const row: { [columnName: string ]: string } = {};
rowStr.split(',').forEach((cell, i) => {
row[headerColumns[i]] = cell;
});
return rows;
});
}
- ๋ฐ๋ฉด ์ด ์ด๋ฆ์ ์๊ณ ์๋ ํน์ ํ ์ํฉ์ด๋ผ๋ฉด ๋ฏธ๋ฆฌ ์ ์ธํด ๋ ํ์ ์ผ๋ก ๋จ์ธ๋ฌธ์ ์ฌ์ฉํ๋ค.
interface ProductRow {
productId: string;
name: string;
price: string;
}
declare let csvData: string;
const products = parseCSV(csvData) as unknown as ProductRow[];
// ์ ์ธํด ๋ ์ด๋ค์ด ๋ฐํ์์ ์ค์ ๋ก ์ผ์นํ๋ค๋ ๋ณด์ฅ์ด ์๊ธฐ ๋๋ฌธ์ ์ด ๋ถ๋ถ์ด ๊ฑฑ์ ๋๋ค๋ฉด ๊ฐ ํ์
์ undefined๋ฅผ ์ถ๊ฐํ ์ ์๋ค.
function safeParseCSV(input: string): { [columnName: string]: string | undefined }[] {
return parseCSV(input);
}
// ๋ชจ๋ ์ด์ undefined ์ฌ๋ถ๋ฅผ ์ฒดํฌํด์ผ ํ๋ค.
const rows = parseCSV(csvData);
const prices: { [product: string]: number } = {};
for (const row of rows) {
prices[row.productId] = Number(row.price);
}
const saveRows = safeParseCSV(csvData);
for (const row of safeRows) {
prices[row.productId] = Number(row.price); // 'undefined' ํ์์ ์ธ๋ฑ์ค ํ์์ผ๋ก ์ฌ์ฉํ ์ ์๋ค.
}
- ์ด๋ค ํ์ ์ ๊ฐ๋ฅํ ํ๋๊ฐ ์ ํ๋์ด ์๋ ๊ฒฝ์ฐ๋ผ๋ฉด ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๋ก ๋ชจ๋ธ๋งํ์ง ๋ง์์ผ ํ๋ค.
interface Row1 {
[column: string]: number
} // ๋๋ฌด ๊ด๋ฒ์
interface Row2 {
a?: number;
b?: number;
c?: number;
d?: number;
} // ์ต์
// 1) Record๋ฅผ ์ฌ์ฉํ์ฌ ํค ํ์
์ ์ ์ฐ์ฑ ์ ๊ณต
type Vec3D = Record<'x' | 'y' | 'z', number>;
// 2) mapped type
type Vec3D = { [k in 'x' | 'y' | 'z']: number };
// ์์ฉ) ์กฐ๊ฑด๋ถ ํ์
๊ณผ ์ฐ๊ฒฐ
type ABC = { [k in 'a' | 'b' | 'c']: k extends 'b' ? string : number };
// Type ABC = {
// a: number;
// b: string;
// c: number;
// }