πŸ“š λŸ¬λ‹ νƒ€μž…μŠ€ν¬λ¦½νŠΈ μ±… 리뷰 | ν•¨μˆ˜, λ°°μ—΄, μΈν„°νŽ˜μ΄μŠ€

졜근 λŸ¬λ‹ νƒ€μž…μŠ€ν¬λ¦½νŠΈ 책을 μ΄μš©ν•΄ νƒ€μž…μŠ€ν¬λ¦½νŠΈ μŠ€ν„°λ””λ₯Ό μ§„ν–‰ν•˜κ³ μžˆλ‹€.

5μž₯.ν•¨μˆ˜, 6μž₯.λ°°μ—΄, 7μž₯.μΈν„°νŽ˜μ΄μŠ€ 챕터λ₯Ό 읽으며 μΈμƒμ μ΄μ—ˆλ˜ λ‚΄μš©μ„ μœ„μ£Όλ‘œ 정리해보렀 ν•œλ‹€.

1. ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜μ˜ νƒ€μž… μΆ”λ‘  방식

κΈ°λ³Έ ν•¨μˆ˜ λ§€κ°œλ³€μˆ˜μ—μ„œλ„ 초기 λ³€μˆ«κ°’κ³Ό μœ μ‚¬ν•˜κ²Œ νƒ€μž… 좔둠이 이루어진닀.

function rateSong(song: string, rating = 0) {
  console.log(`${song} gets ${rating}/5 stars`);
}

rateSong("Photograph"); //ok
rateSong("Set Fire to the Rain", 5); //ok
rateSong("Set Fire to The Rain", undefined); //ok

rateSong("At Last!", "100"); // error

songμ—λŠ” stringνƒ€μž…μ„ λͺ…μ‹œμ μœΌλ‘œ μ„ μ–Έν•΄μ€¬μ§€λ§Œ ratingμ—λŠ” μ΄ˆκΈ°κ°’λ§Œ ν• λ‹Ήλ˜μ–΄μžˆκ³  λ”°λ‘œ νƒ€μž… μ• λ„ˆν…Œμ΄μ…˜μ΄ μ—†λ‹€.

κ·ΈλŸ¬λ‚˜ νƒ€μž…μŠ€ν¬λ¦½νŠΈλŠ” μœ„μ™€ 같은 경우 λ§€κ°œλ³€μˆ˜μ˜ μ΄ˆκΈ°κ°’μ„ 기반으둜 νƒ€μž…μ„ μœ μΆ”ν•œλ‹€.

μΈμƒμ μ΄μ—ˆλ˜ 뢀뢄은 rating의 νƒ€μž… 좔둠이 ν•¨μˆ˜λ₯Ό ν˜ΈμΆ­ν•˜λŠ” μ½”λ“œμ—μ„œλŠ” number νƒ€μž…μœΌλ‘œ μœ μΆ”λ˜μ§€λ§Œ, ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λŠ”(μ‚¬μš©ν•˜λŠ”) μ½”λ“œμ—μ„œλŠ” 선택적 number | undefined둜 μœ μΆ”λœλ‹€λŠ” 점이닀.

thinking emoji
ν•¨μˆ˜ μ„ μ–ΈλΆ€ - rating의 νƒ€μž…μ΄ number둜 μœ μΆ”λ˜μ—ˆλ‹€.
thinking emoji
ν•¨μˆ˜ ν˜ΈμΆœλΆ€ - rating의 νƒ€μž…μ΄ number | undefined둜 μœ μΆ”λ˜μ—ˆλ‹€.

즉, ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜μ˜ μ΄ˆκΉƒκ°’μ„ μ§€μ •ν•˜λ©΄ μžλ™μ μœΌλ‘œ ν•΄λ‹Ή νƒ€μž… | undefined둜 μ§€μ •λœλ‹€.

2. ?으둜 ν‘œν˜„λ˜λŠ” 선택적 λ§€κ°œλ³€μˆ˜μ™€ undefinedλ₯Ό ν¬ν•¨ν•˜λŠ” μœ λ‹ˆμ–Έ νƒ€μž…μ˜ 차이

// | undefinedλ₯Ό ν¬ν•¨ν•˜λŠ” μœ λ‹ˆμ–Έ νƒ€μž…
function getSingerA(singer: string | undefined) {}
// 선택적 λ§€κ°œλ³€μˆ˜
function getSingerB(singer?: string) {}

getSingerA("Greensleeves"); // error
getSingerB("Greensleeves"); // ok

getSingerA(undefined); // ok
getSingerB(undefined); // ok

getSingerA("Sia"); //ok
getSingerB("Sia"); //ok

λ§‰μ—°ν•˜κ²Œ νƒ€μž…μ— ?으둜 ν‘œμ‹œν•˜λ©΄ undefinedλ₯Ό μœ λ‹ˆμ˜¨νƒ€μž…μ„ μΆ”κ°€ν•œ 것과 μœ μ‚¬ν•˜μ§€μ•Šμ„κΉŒ? 라고 μƒκ°ν•˜κ³ μžˆμ—ˆλ‹€.

ν•˜μ§€λ§Œ ?둜 ν‘œμ‹œν•œ 것은 λ§€κ°œλ³€μˆ˜ 자체λ₯Ό μ„ νƒμ μœΌλ‘œ 받겠닀라고 μ •μ˜ν•˜λŠ” 것이고, 선택적 λ§€κ°œλ³€μˆ˜ 없이 | undefinedλ₯Ό ν¬ν•¨ν•˜λŠ” μœ λ‹ˆμ–Έ νƒ€μž…μœΌλ‘œ μ„ μ–Έν•˜λŠ” 것은 값을 무쑰건 λ°›λ˜, undefined도 κ°€λŠ₯ν•˜κ²Œλ” νƒ€μž…μ„ μ„ μ–Έν•œ κ²ƒμ΄λΌλŠ” μ μ—μ„œ 이 λ‘˜μ€ λ‹€λ₯΄λ‹€.

3. λ°˜ν™˜ νƒ€μž…μœΌλ‘œ void vs undefined vs never

  • void: ν•¨μˆ˜μ˜ λ°˜ν™˜ νƒ€μž…μ΄ λ¬΄μ‹œλœλ‹€. ν•¨μˆ˜κ°€ λ°˜ν™˜ν•˜λŠ” λͺ¨λ“  값을 λ¬΄μ‹œν•˜λ„λ‘ μ„€μ •ν•  λ•Œ μœ μš©ν•˜λ‹€.
    • ex) μžλ°”μŠ€ν¬λ¦½νŠΈ λ‚΄μž₯ ν•¨μˆ˜ forEach() λ©”μ„œλ“œλŠ” voidλ₯Ό λ°˜ν™˜ν•˜λŠ” μ½œλ°±μ„ λ°›λŠ”λ‹€.
  • undefined: λ§κ·ΈλŒ€λ‘œ undefinedκ°€ λ°˜ν™˜λœλ‹€λŠ” 것을 λͺ…μ‹œμ μœΌλ‘œ μ„ μ–Έν•œ 것.
  • never νƒ€μž…: (μ˜λ„μ μœΌλ‘œ) 항상 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚€κ±°λ‚˜ λ¬΄ν•œλ£¨ν”„λ₯Ό μ‹€ν–‰ν•˜λŠ” ν•¨μˆ˜. μ ˆλŒ€ λ°˜ν™˜ν•˜μ§€ μ•ŠλŠ”λ‹€.

voidλŠ” 아무것도 λ°˜ν™˜ν•˜μ§€ μ•ŠλŠ” ν•¨μˆ˜λ₯Ό ν‘œν˜„ν•  λ•Œ, neverλŠ” μ ˆλŒ€ λ°˜ν™˜ν•˜μ§€ μ•ŠλŠ” ν•¨μˆ˜μ˜ νƒ€μž…μ„ ν‘œν˜„ν•  λ•Œ μ‚¬μš©ν•œλ‹€.

3-1. never의 λ˜λ‹€λ₯Έ μš©λ²•: λ³΅μž‘ν•œ 쑰건 νƒ€μž… ν‘œν˜„ν•˜κΈ°.

예λ₯Ό λ“€λ©΄ 이런 κ²½μš°μ΄λ‹€.

μ–΄λ–€ ν•¨μˆ˜λŠ” 2κ°€μ§€μ˜ λ§€κ°œλ³€μˆ˜λ₯Ό 받을 수 μžˆλ‹€. κ·ΈλŸ¬λ‚˜ number 인자λ₯Ό λ°›μœΌλ©΄ string은 받을 수 μ—†κ³ , λ°˜λŒ€λ‘œ string을 λ°›μœΌλ©΄ numberλŠ” 받을 수 μ—†λ‹€.

μ΄λŸ¬ν•œ 쑰건을 가진 ν•¨μˆ˜μ˜ νƒ€μž…μ„ μ •μ˜ν•  λŒ€ μ•„λž˜μ™€ 같이 선택적 λ§€κ°œλ³€μˆ˜μ™€ never νƒ€μž…μ„ μ΄μš©ν•΄ νƒ€μž… μ •μ˜λ₯Ό ν•  수 μžˆλ‹€.

interface TextOnly {
  number?: never;
  string: string;
}
interface NumberOnly {
  number: number;
  string?: never;
}

type Interface = TextOnly | NumberOnly;

function foo({ number, string }: Interface) {
  // ...
}

foo({ number: 1, string: "a" }); // error
foo({ number: 1 }); // ok
foo({ string: "a" }); //ok

4. enum을 μ‚¬μš©ν•˜λŠ” 것은 μ„±λŠ₯λ©΄μ—μ„œ 쒋지 μ•Šλ‹€!

enumμ΄λž€ μ—΄κ±°ν˜• λ³€μˆ˜λ‘œ Javascriptμ—μ„œλŠ” μ œκ³΅ν•˜μ§€ μ•ŠλŠ” Typescriptκ°€ 자체적으둜 κ΅¬ν˜„ν•˜λŠ” κΈ°λŠ₯이닀.

enum을 μ‚¬μš©ν•œ μ½”λ“œλ₯Ό μ»΄νŒŒμΌν•˜κ²Œ 되면 λ‹€μŒκ³Ό 같은 κ²°κ³Όλ₯Ό 얻을 수 μžˆλ‹€.

export enum FRUITS {
  APPLE = 'apple',
  BANANA = 'banana'
};

[컴파일 결과]

export var FRUITS;
(function (FRUITS) {
  FRUITS["APPLE"] = "apple";
  FRUITS["BANANA"] = "banana";
})(FRUITS || (FRUITS = {}));

μœ„μ™€ 같이 μ¦‰μ‹œμ‹€ν–‰ν•¨μˆ˜μ˜ ν˜•νƒœλ‘œ 객체λ₯Ό λ§Œλ“€κ²Œ λ˜λŠ”λ°, 이 μ½”λ“œλŠ” λ²ˆλ“€λŸ¬κ°€ β€˜μ‚¬μš©ν•˜μ§€ μ•ŠλŠ”β€™μ½”λ“œλΌκ³  νŒλ‹¨ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ νŠΈλ¦¬μ‰μ΄ν‚Ήλ˜μ§€ μ•Šκ³  μ΅œμ’… λ²ˆλ“€μ— ν¬ν•¨λœλ‹€. 즉, 개발 ν™˜κ²½μ—μ„œλ§Œ ν•„μš”ν•œ λΆˆν•„μš”ν•œ νƒ€μž… μ •μ˜ μ½”λ“œλ‘œ 인해 λ²ˆλ“€μ˜ 크기가 μ¦κ°€ν•˜κ²Œ λ˜λŠ” 것이닀.

μ΄λŸ¬ν•œ enum νƒ€μž…μ„ λŒ€μ²΄ν•˜κΈ°μœ„ν•œ λ°©λ²•μœΌλ‘œ const μ–΄μ„œμ…˜μ„ μ‚¬μš©ν•  수 μžˆλ‹€.

export const FruitsType = {
  APPLE = 'apple',
  BANANA = 'banana'
} as const;

export type FruitsType = keyof typeof FruitsType;

5. 배열은 λΆˆμ•ˆμ •ν•˜λ‹€.

Typescript의 νƒ€μž… μ‹œμŠ€ν…œμ€ μ™„λ²½ν•˜μ§€ μ•Šλ‹€. Typescriptμ—μ„œλŠ” 기본적으둜 λͺ¨λ“  λ°°μ—΄μ˜ 멀버에 λŒ€ν•œ 접근에 λŒ€ν•΄ ν•΄λ‹Ή λ°°μ—΄μ˜ 멀버λ₯Ό λ°˜ν™˜ν•œλ‹€κ³  κ°€μ •ν•œλ‹€. 즉, μ–΄λ–€ λ°°μ—΄μ˜ ν•΄λ‹Ή μΈλ±μŠ€μ— μ‹€μ œλ‘œ 값이 μ‘΄μž¬ν•˜μ§€ μ•Šμ•„λ„ μ‘΄μž¬ν•œλ‹€κ³  κ°€μ •ν•œλ‹€. (μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œλ„ 배열에 λŒ€ν•΄μ„œλŠ” λΉ„μŠ·ν•œ λ°©μ‹μœΌλ‘œ λ™μž‘ν•œλ‹€. λ§Œμ•½, λ°°μ—΄μ˜ 길이보닀 큰 인덱슀둜 λ°°μ—΄ μš”μ†Œμ— μ ‘κ·Όν•˜λ©΄ 레퍼런슀 μ—λŸ¬κ°€ μ•„λ‹Œ undefinedλ₯Ό μ œκ³΅ν•œλ‹€.)

function withElement(elements: string[]) {
  console.log(elements[9001].length); // νƒ€μž… 였λ₯˜ λ°œμƒν•˜μ§€ μ•ŠμŒ
}

withElements(["It's", "over"]);

TypescriptλŠ” κ²€μƒ‰λœ λ°°μ—΄μ˜ 멀버가 μ‘΄μž¬ν•˜λŠ”μ§€ μ˜λ„μ μœΌλ‘œ ν™•μΈν•˜μ§€ μ•ŠμœΌλ―€λ‘œ μœ„μ™€ 같은 μƒν™©μ—μ„œ νƒ€μž… 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚€μ§€ μ•ŠλŠ”λ‹€. λ˜ν•œ elements[9001]λŠ” undefinedκ°€ μ•„λ‹ˆλΌ string νƒ€μž…μœΌλ‘œ κ°„μ£Όλœλ‹€.

μ§€κΈˆκΉŒμ§€ κ°œλ°œμ„ ν•˜λŠ” κ³Όμ •μ—μ„œλŠ” μ„€λ Ή μœ„μ™€ 같은 상황이 생겼더라도 νƒ€μž… 였λ₯˜κ°€ λ°œμƒν•˜μ§€ μ•ŠλŠ” 것에 λŒ€ν•΄ 큰 μ˜λ¬Έμ„ 갖지 μ•Šμ•˜μ„ 것 κ°™λ‹€. ν•˜μ§€λ§Œ 이 책을 톡해 예제λ₯Ό μ ‘ν•΄λ³΄λ‹ˆ νƒ€μž…μŠ€ν¬λ¦½νŠΈλ₯Ό 기술적으둜 λΆˆμ•ˆμ •ν•˜λ‹€κ³  ν•˜λŠ” κ²ƒμ˜ 의미λ₯Ό 이해할 수 μžˆμ—ˆκ³  ν₯λ―Έλ‘œμ› λ‹€.

이번 νŒŒνŠΈμ™€ 예제λ₯Ό 톡해 νƒ€μž…μŠ€ν¬λ¦½νŠΈμ™€ μžλ°”μŠ€ν¬λ¦½νŠΈκ°€ μ™„λ²½ν•˜μ§€ μ•Šλ‹€λŠ” κ±Έ 더 잘 μ΄ν•΄ν•˜κ²Œ λ˜μ—ˆκ³ , 이 사싀을 μ•Œκ³  λ‚˜λ‹ˆ μ•žμœΌλ‘œ 이런 μ½”λ“œ μž‘μ„±ν•  λ•Œ 쑰금 더 μ‹ κ²½ μ“°κ²Œ 될 것 κ°™λ‹€.

μ°Έκ³ 

https://beta.reactjs.org/reference/react/useLayoutEffect

https://all-dev-kang.tistory.com/entry/%EB%A6%AC%EC%95%A1%ED%8A%B8-useEffect%EC%99%80-useLayoutEffect-%EB%B9%84%EA%B5%90%EC%8B%9C%EB%A6%AC%EC%A6%88

https://engineering.linecorp.com/ko/blog/typescript-enum-tree-shaking