# ๐ Item16 ~ 18
# Item16. number ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๋ณด๋ค๋ Array, ํํ, ArrayLike๋ฅผ ์ฌ์ฉํ๊ธฐ
Array
์ ๋ํ ํ์ ์ ์ธ(lib.es5.d.ts
์์ ํ์ธ ๊ฐ๋ฅ)
interface Array<T> {
// ...
[n: number]: T;
}
- ๋ฐํ์์๋ ECMAScript ํ์ค์ด ์์ ํ๋ ๊ฒ์ฒ๋ผ ๋ฌธ์์ด ํค๋ก ์ธ์ํ๋ฏ๋ก ์ด ์ฝ๋๋ ์์ ํ ๊ฐ์์ด๋ผ๊ณ ํ ์ ์์ง๋ง, ํ์ ์ฒดํฌ ์์ ์ ์ค๋ฅ๋ฅผ ์ก์ ์ ์์ด ์ ์ฉํ๋ค.
const xs = [1, 2, 3];
const x0 = xs[0]; // ์ ์
const x1 = xs['1']; // ์ธ๋ฑ์ค ์์ด 'number' ํ์์ด ์๋๋ฏ๋ก ์์์ ์์์ ์ผ๋ก 'any' ํ์์ด ์์ต๋๋ค.
function get<T>(array: T[], k: string): T {
return array[k]; // ์ธ๋ฑ์ค ์์ด 'number' ํ์์ด ์๋๋ฏ๋ก ์์์ ์์์ ์ผ๋ก 'any' ํ์์ด ์์ต๋๋ค.
}
- ํํธ
Object.keys
๊ฐ์ ๊ตฌ๋ฌธ์ ์ฌ์ ํ ๋ฌธ์์ด๋ก ๋ฐํ๋๋ค.string
์ดnumber
์ ํ ๋น๋ ์ ์๊ธฐ ๋๋ฌธ์ ์๋ ์ฝ๋์ ๋ง์ง๋ง ์ค์ด ๋์ํ๋ ๊ฒ์ด ์ด์ํ๊ฒ ๋ณด์ผ ๊ฒ์ด๋ค.- ์๋ฐ์คํฌ๋ฆฝํธ์์๋ ํํ ์ผ์ด์ง๋ง, ์ด ์์ ๊ฐ ๋ฐฐ์ด์ ์ํํ๊ธฐ์ ์ข์ ๋ฐฉ๋ฒ์ ์๋๋ค.
const keys = Object.keys(xs); // ํ์
์ด string[]
for (const key in xs) {
key; // ํ์
์ด string
const x = xs[key]; // ํ์
์ด number
}
- ์ธ๋ฑ์ค์ ์ ๊ฒฝ ์ฐ์ง ์๋๋ค๋ฉด,
for~of
๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ๋ ์ข๋ค.
for (const x of xs) {
x; // ํ์
์ด number
}
- ๋ง์ฝ ์ธ๋ฑ์ค์ ํ์
์ด ์ค์ํ๋ค๋ฉด,
number
ํ์ ์ ์ ๊ณตํด ์คArray.prototype.forEach
๋ฅผ ์ฌ์ฉํ๋ฉด ๋๋ค.
xs.forEach((x, i) => {
i; // ํ์
์ด number
x; // ํ์
์ด number
})
- ๋ฃจํ ์ค๊ฐ์ ๋ฉ์ถฐ์ผ ํ๋ค๋ฉด, C ์คํ์ผ์ธ
for(;;)
๋ฃจํ๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
for (let i = 0; i < xs.length; i++) {
const x = xs[i];
if (x < 0) break;
}
- ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๊ฐ
number
๋ก ํํ๋์ด ์๋ค๋ฉด ์ ๋ ฅํ ๊ฐ์ดnumber
์ฌ์ผ ํ๋ค๋ ๊ฒ์ ์๋ฏธํ์ง๋ง(for~in
๋ฃจํ๋ ํ์คํ ์ ์ธ), ์ค์ ๋ฐํ์์ ์ฌ์ฉ๋๋ ํค๋string
ํ์ ์ด๋ค.number
๋ฅผ ์ธ๋ฑ์ค ํ์ ์ผ๋ก ์ฌ์ฉํ๋ฉด ์ซ์ ์์ฑ์ด ์ด๋ค ํน๋ณํ ์๋ฏธ๋ฅผ ์ง๋๋ค๋ ์คํด๋ฅผ ๋ถ๋ฌ ์ผ์ผํฌ ์ ์๋ค.
- ์ด๋ค ๊ธธ์ด๋ฅผ ๊ฐ์ง๋ ๋ฐฐ์ด๊ณผ ๋น์ทํ ํํ์ ํํ์ ์ฌ์ฉํ๊ณ ์ถ๋ค๋ฉด ํ์
์คํฌ๋ฆฝํธ์ ์๋
ArrayLike
ํ์ ์ ์ฌ์ฉํ๋ค.
function checkedAccess<T>(xs: ArrayLike<T>, i: number): T {
if (i < xs.length) {
return xs[i];
}
throw new Error(`๋ฐฐ์ด์ ๋์ ์ง๋์ ${i}๋ฅผ ์ ๊ทผํ๋ ค๊ณ ํ์ต๋๋ค.`);
}
๐ก ๊ฒฐ๋ก !
- ๋ฐฐ์ด์ ๊ฐ์ฒด์ด๋ฏ๋ก ํค๋ ์ซ์๊ฐ ์๋๋ผ ๋ฌธ์์ด์ด๋ค.
- ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๋ก ์ฌ์ฉ๋
number
ํ์ ์ ๋ฒ๊ทธ๋ฅผ ์ก๊ธฐ ์ํ ์์ ํ์ ์คํฌ๋ฆฝํธ ์ฝ๋์ด๋ค.
- ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๋ก ์ฌ์ฉ๋
- ์ธ๋ฑ์ค ์๊ทธ๋์ฒ์
number
๋ฅผ ์ฌ์ฉํ๊ธฐ๋ณด๋คArray
๋ ํํ, ๋๋ArrayLike
ํ์ ์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข๋ค.
# Item17. ๋ณ๊ฒฝ ๊ด๋ จ๋ ์ค๋ฅ ๋ฐฉ์ง๋ฅผ ์ํด readonly ์ฌ์ฉํ๊ธฐ
number
ํ์ ์ ๋ด์ ๋ฐฐ์ด์ ์์๋ก ์๊ฐํด๋ณด์.number[]
๋readonly number[]
๋ณด๋ค ๊ธฐ๋ฅ์ด ๋ง์ผ๋ฏ๋กreadonly number[]
์ ์๋ธํ์ ์ด ๋๋ค.- ๋ฐ๋ผ์ ๋ณ๊ฒฝ ๊ฐ๋ฅํ ๋ฐฐ์ด์
readonly
๋ฐฐ์ด์ ํ ๋นํ ์ ์๊ณ ๊ทธ ๋ฐ๋๋ ๋ถ๊ฐ๋ฅํ๋ค.
const a: number[] = [1, 2, 3];
const b: readonly number[] = a;
const c: number[] = b; // 'readonly number[]' ํ์
์ 'readonly'์ด๋ฏ๋ก ๋ณ๊ฒฝ ๊ฐ๋ฅํ 'number[]' ํ์
์ ํ ๋น๋ ์ ์์ต๋๋ค.
- ๋งค๊ฐ๋ณ์๋ฅผ
readonly
๋ก ์ ์ธํ๋ฉด ์๊ธฐ๋ ์ผ- ํ์ ์คํฌ๋ฆฝํธ๋ ๋งค๊ฐ๋ณ์๊ฐ ํจ์ ๋ด์์ ๋ณ๊ฒฝ์ด ์ผ์ด๋๋์ง ์ฒดํฌํ๋ค.
- ํธ์ถํ๋ ์ชฝ์์๋ ํจ์๊ฐ ๋งค๊ฐ๋ณ์๋ฅผ ๋ณ๊ฒฝํ์ง ์๋๋ค๋ ๋ณด์ฅ์ ๋ฐ๊ฒ ๋๋ค.
- ํธ์ถํ๋ ์ชฝ์์ ํจ์์
readonly
๋ฐฐ์ด์ ๋งค๊ฐ๋ณ์๋ก ๋ฃ์ ์๋ ์๋ค.
- ๋ง์ฝ ํจ์๊ฐ ๋งค๊ฐ๋ณ์๋ฅผ ์์ ํ์ง ์๋๋ค๋ฉด
readonly
๋ก ์ ์ธํ๋ ๊ฒ์ด ์ข๋ค.readonly
๋งค๊ฐ๋ณ์๋ ์ธํฐํ์ด์ค๋ฅผ ๋ช ํํ๊ฒ ํ๋ฉฐ, ๋งค๊ฐ๋ณ์๊ฐ ๋ณ๊ฒฝ๋๋ ๊ฒ์ ๋ฐฉ์งํ๋ค.
readonly
๋ฅผ ์ฌ์ฉํ๋ฉด ๋ณ๊ฒฝํ๋ฉด์ ๋ฐ์ํ๋ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ ์ ์๊ณ , ๋ณ๊ฒฝ์ด ๋ฐ์ํ๋ ์ฝ๋๋ ์ฝ๊ฒ ์ฐพ์ ์ ์๋ค.
# โญ๏ธ const
์ readonly
์ ์ฐจ์ด
function parseTaggedText(lines: string[]): string[][] {
const paragraph: string[][] = [];
const currPara: string[] = [];
const addParagraph = () => {
if (currPara.length) {
paragraphs.push(currPara);
currPara.length = 0; // ๋ฐฐ์ด์ ๋น์
}
};
for (const line of lines) {
if (!line) {
addParagraph();
} else {
currPara.push(line);
}
}
addParagraph();
return paragraphs;
}
- ์ ์ฝ๋๋ฅผ ์คํํ๋ฉด
[[], [], []]
์ ๊ฐ์ ์๋ชป๋ ๊ฒฐ๊ณผ๊ฐ ์ถ๋ ฅ๋๋ค. - ๋ฐฐ์ด์ ๋น์ฐ๋ ์ฝ๋ ๋ถ๋ถ์ด ๋ฌธ์ ์ธ๋ฐ ์ด ๋
currPara
๋ฅผreadonly
๋ก ์ ์ธํ์ฌ ์ค๋ฅ๋ฅผ ๋ฐฉ์งํ ์ ์๋ค.
function parseTaggedText(lines: string[]): string[][] {
const paragraph: string[][] = [];
// ์ ์ธ๋ถ๋ฅผ let์ ๋ฐ๊พธ๊ณ readonly๋ฅผ ์ถ๊ฐํจ์ผ๋ก์จ ํ์ชฝ์ ๋ณ๊ฒฝ ๊ฐ๋ฅ์ฑ์ ๋ ๋ค๋ฅธ ์ชฝ์ผ๋ก ์ฎ๊ธด ๊ฒ์ด๋ค.
// currPara ๋ณ์๋ ๊ฐ๋ฆฌํค๋ ๋ฐฐ์ด์ ์์ ๋กญ๊ฒ ๋ณ๊ฒฝํ ์ ์์ง๋ง, ๊ทธ ๋ฐฐ์ด ์์ฒด๋ ๋ณ๊ฒฝํ์ง ๋ชปํ๊ฒ ๋๋ค.
let currPara: readonly string[] = [];
const addParagraph = () => {
if (currPara.length) {
paragraphs.push(currPara);
currPara = []; // ๋ฐฐ์ด์ ๋น์
}
};
for (const line of lines) {
if (!line) {
addParagraph();
} else {
currPara = currPara.concat([line]); // push์ ๋ฌ๋ฆฌ concat์ ์๋ณธ์ ์์ ํ์ง ์๊ณ ์ ๋ฐฐ์ด์ ๋ฐํํจ
}
}
addParagraph();
return paragraphs;
}
ํ์ง๋ง ์ฌ์ ํ
parargraphs
์ ๋ํ ์ค๋ฅ๋ ๋จ์ ์๋ค. ํด๊ฒฐ ๋ฐฉ๋ฒ์ ์ด ์ธ ๊ฐ์ง ์ด๋ค.currPara
์ ๋ณต์ฌ๋ณธ์ ๋ง๋๋ ๋ฐฉ๋ฒcurrPara
๋readonly
๋ก ์ ์ง๋์ง๋ง, ๋ณต์ฌ๋ณธ์ ์ํ๋ ๋๋ก ๋ณ๊ฒฝ์ด ๊ฐ๋ฅํ๋ฏ๋ก ์ค๋ฅ๋ ์ฌ๋ผ์ง๋ค.
paragraphs.push([...currPara]);
paragraphs
(๊ทธ๋ฆฌ๊ณ ํจ์์ ๋ฐํ ํ์ )๋ฅผreadonly string[]
์ ๋ฐฐ์ด๋ก ๋ณ๊ฒฝํ๋ ๋ฐฉ๋ฒ
const paragraphs: (readonly string[])[] = [];
- ๋ฐฐ์ด์
readonly
์์ฑ์ ์ ๊ฑฐํ๊ธฐ ์ํ ๋จ์ธ๋ฌธ์ ์ฐ๋ ๋ฐฉ๋ฒ
paragraphs.push(currPara as string[]);
readonly
๋ ์๊ฒ ๋์ํ๋ค๋ ๊ฒ์ ์ ์ํด์ผ ํ๋ค.- ๋ง์ฝ ๊ฐ์ฒด์
readonly
๋ฐฐ์ด์ด ์๋ค๋ฉด, ๊ทธ ๊ฐ์ฒด ์์ฒด๋readonly
๊ฐ ์๋๋ค.
- ๋ง์ฝ ๊ฐ์ฒด์
const dates: readonly Date[] = [new Date()];
dates.push(new Date()); // ~~~ 'readonly Date[]' ํ์์ 'push' ์์ฑ์ด ์์ต๋๋ค.
dates[0].setFullYear(2037); // ์ ์
- ๋น์ทํ ๊ฒฝ์ฐ๋ก
Readonly
์ ๋ค๋ฆญ์ด ์๋ค.
interface Outer {
inner: {
x: number;
}
}
const o: Readonly<Outer> = { inner: { x: 0 } };
o.inner = { x: 1 }; // ~~~ ์ฝ๊ธฐ ์ ์ฉ ์์ฑ์ด๊ธฐ ๋๋ฌธ์ 'inner'์ ํ ๋นํ ์ ์์ต๋๋ค/
o.inner.x = 1; // ์ ์
์ค์ํ ์ ์
readonly
์ ๊ทผ์ ์ด์๋inner
์ ์ ์ฉ๋๋ ๊ฒ์ด์งx
๋ ์๋๋ผ๋ ๊ฒ์ด๋ค.- ํ์ฌ ์์ ์๋ ๊น์
readonly
ํ์ ์ด ๊ธฐ๋ณธ์ผ๋ก ์ง์๋์ง ์์ง๋ง, ์ ๋ค๋ฆญ์ ๋ง๋ค๋ฉด ๊น์readonly
ํ์ ์ ์ฌ์ฉํ ์ ์๋ค. - ๊ทธ๋ฌ๋ ์ ๋ค๋ฆญ์ ๋ง๋๋ ๊ฒ์ ๊น๋ค๋กญ๊ธฐ ๋๋ฌธ์
ts-essentials
์ ์๋DeepReadonly
์ ๋ค๋ฆญ์ ์ฌ์ฉํ๋ฉด ๋๋ค.
- ํ์ฌ ์์ ์๋ ๊น์
์ธ๋ฑ์ค ์๊ทธ๋์ฒ์๋
readonly
๋ฅผ ์จ์ ์ฝ๊ธฐ๋ ํ์ฉํ๋ ์ฐ๊ธฐ๋ฅผ ๋ฐฉ์งํ ์ ์๋ค.
let obj: { readonly [k: string]: number } = {};
// ๋๋ Readonly<{[k: string]: number}>
obj.hi = 45; // ~~ ํ์์ ์ธ๋ฑ์ค ์๊ทธ๋์ฒ๋ ์ฝ๊ธฐ๋ง ํ์ฉ๋ฉ๋๋ค.
obj = {...obj, hi: 12}; // ์ ์
obj = {...obj, bye: 345}; // ์ ์
# Item18. ๋งคํ๋ ํ์ ์ ์ฌ์ฉํ์ฌ ๊ฐ์ ๋๊ธฐํํ๊ธฐ
interface ScatterProps {
// The Data
xs: number[];
ys: number[];
// Display
xRange: [number, number];
yRange: [number, number];
// Events
onClick: (x: number, y: number, index: number) => void;
}
const REQUIRES_UPDATE: {[k in keyof ScatterProps]: boolean} = {
xs: true,
ys: true,
xRange: true,
yRange: true,
color: true,
onClick: false,
};
function shouldUpdate(
oldProps: ScatterProps,
newProps: ScatterProps
) {
let k: keyof ScatterProps;
for (k in oldProps) {
if (oldProps[k] !== newProps[k] && REQUIRES_UPDATE[K]) {
return true;
}
}
return false;
}
[k in keyof ScatterProps]
์ ํ์ ์ฒด์ปค์๊ฒREQUIRES_UPDATE
๊ฐScatterProps
๊ณผ ๋์ผํ ์์ฑ์ ๊ฐ์ ธ์ผ ํ๋ค๋ ์ ๋ณด๋ฅผ ์ ๊ณตํ๋ค.- ๋์ค์
ScatterProps
์ ์๋ก์ด ์์ฑ์ ์ถ๊ฐํ๋ ๊ฒฝ์ฐ ๋ค์ ์ฝ๋์ ๊ฐ์ ํํ๊ฐ ๋ ๊ฒ์ด๊ณREQUIRES_UPDATE
์ ์ ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
interface ScatterProps {
// ...
onDoubleClick: () => void;
}
const REQUIRES_UPDATE: {[k in keyof ScatterProps]: boolean} = {
// ~~~ 'onDoubleClick' ์์ฑ์ด ํ์
์ ์์ต๋๋ค.
}
- ๋ง์ฝ ๋ฐฐ์ด์ ์ฌ์ฉํ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ์ฝ๋๊ฐ ๋๋ค.
const PROPS_REQUIRING_UPDATE: (keyof ScatterProps)[] = [
'xs',
'ys',
// ...
];
- ๋งคํ๋ ํ์ ์ ํ ๊ฐ์ฒด๊ฐ ๋ ๋ค๋ฅธ ๊ฐ์ฒด์ ์ ํํ ๊ฐ์ ์์ฑ์ ๊ฐ์ง๊ฒ ํ ๋ ์ด์์ ์ด๋ค.
- ๋งคํ๋ ํ์ ์ ์ฌ์ฉํด์ ๊ด๋ จ๋ ๊ฐ๊ณผ ํ์ ์ ๋๊ธฐํํ๋๋ก ํ๋ค.
- ์ธํฐํ์ด์ค์ ์๋ก์ด ์์ฑ์ ์ถ๊ฐํ ๋, ์ ํ์ ๊ฐ์ ํ๋๋ก ๋งคํ๋ ํ์ ์ ๊ณ ๋ คํด์ผ ํ๋ค.