본문으둜 κ±΄λ„ˆλ›°κΈ°

🐀 Chapter 5. any 닀루기

πŸ₯• μ•„μ΄ν…œ 38. any νƒ€μž…μ€ κ°€λŠ₯ν•œ ν•œ 쒁은 λ²”μœ„μ—μ„œλ§Œ μ‚¬μš©ν•˜κΈ°β€‹

function processBar(b: Bar) { /* ... */ }

function f() {
const x = expressionReturnFoo();
processBar(x);
// ~ 'Foo' ν˜•μ‹μ˜ μΈμˆ˜λŠ” 'Bar' ν˜•μ‹μ˜ λ§€κ°œλ³€μˆ˜μ— 할당될 수 μ—†μŠ΅λ‹ˆλ‹€.
}

λ¬Έλ§₯μƒμœΌλ‘œ xλΌλŠ” λ³€μˆ˜κ°€ λ™μ‹œμ— Foo νƒ€μž…κ³Ό Bar νƒ€μž…μ— ν• λ‹Ή κ°€λŠ₯ν•˜λ‹€λ©΄, 였λ₯˜λ₯Ό μ œκ±°ν•˜λŠ” 방법은 두 κ°€μ§€μž…λ‹ˆλ‹€.

function f1() {
const x: any = expressionReturnFoo(); // μ΄λ ‡κ²Œ ν•˜μ§€ λ§™μ‹œλ‹€.
processBar(x);
}

function f2() {
const x = expressionReturnFoo();
processBar(x as any); // 이게 λ‚«μŠ΅λ‹ˆλ‹€.
}

두 가지 ν•΄κ²°μ±… μ€‘μ—μ„œ f1에 μ‚¬μš©λœ x: any보닀 f2에 μ‚¬μš©λœ x as any ν˜•νƒœκ°€ ꢌμž₯λ©λ‹ˆλ‹€. κ·Έ μ΄μœ λŠ” any νƒ€μž…μ΄ processBar ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜μ—μ„œλ§Œ μ‚¬μš©λœ ν‘œν˜„μ‹μ΄λ―€λ‘œ λ‹€λ₯Έ μ½”λ“œμ—λŠ” 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠκΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€.

λΉ„μŠ·ν•œ κ΄€μ μ—μ„œ, νƒ€μž…μŠ€ν¬λ¦½νŠΈκ°€ ν•¨μˆ˜μ˜ λ°˜ν™˜ νƒ€μž…μ„ μΆ”λ‘ ν•  수 μžˆλŠ” κ²½μš°μ—λ„ ν•¨μˆ˜μ˜ λ°˜ν™˜ νƒ€μž…μ„ λͺ…μ‹œν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€. ν•¨μˆ˜μ˜ λ°˜ν™˜ νƒ€μž…μ„ λͺ…μ‹œν•˜λ©΄ any νƒ€μž…μ˜ ν•¨μˆ˜ λ°”κΉ₯으둜 영ν–₯을 λ―ΈμΉ˜λŠ” 것을 방지할 수 μžˆμŠ΅λ‹ˆλ‹€.

f1은 였λ₯˜λ₯Ό μ œκ±°ν•˜κΈ° μœ„ν•΄ xλ₯Ό any νƒ€μž…μœΌλ‘œ μ„ μ–Έν–ˆμŠ΅λ‹ˆλ‹€. ν•œνŽΈ f2λŠ” 였λ₯˜λ₯Ό μ œκ±°ν•˜κΈ° μœ„ν•΄ xκ°€ μ‚¬μš©λ˜λŠ” 곳에 as any 단언문을 μ‚¬μš©ν–ˆμŠ΅λ‹ˆλ‹€. μ—¬κΈ°μ„œ @ts-ignoreλ₯Ό μ‚¬μš©ν•˜λ©΄ anyλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šκ³  였λ₯˜λ₯Ό μ œκ±°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

function f1() {
const x = expressionReturnFoo();
// @ts-ignore
processBar(x);
return x;
}

κ·ΈλŸ¬λ‚˜ 근본적인 원인을 ν•΄κ²°ν•œ 것이 μ•„λ‹ˆκΈ° λ•Œλ¬Έμ— λ‹€λ₯Έ κ³³μ—μ„œ 더 큰 λ¬Έμ œκ°€ λ°œμƒν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. νƒ€μž… 체컀가 μ•Œλ € μ£ΌλŠ” 였λ₯˜λŠ” λ¬Έμ œκ°€ 될 κ°€λŠ₯성이 높은 λΆ€λΆ„μ΄λ―€λ‘œ 근본적인 원인을 μ°Ύμ•„ 적극적으둜 λŒ€μ²˜ν•˜λŠ” 것이 λ°”λžŒμ§ν•©λ‹ˆλ‹€.
μ΄λ²ˆμ—λŠ” 객체와 κ΄€λ ¨ν•œ any의 μ‚¬μš©λ²•μ„ μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€. μ–΄λ–€ 큰 객체 μ•ˆμ˜ ν•œ 개 속성이 νƒ€μž… 였λ₯˜λ₯Ό κ°€μ§€λŠ” 상황을 예둜 λ“€μ–΄ λ³΄κ² μŠ΅λ‹ˆλ‹€.

const config: Config = {
a: 1,
b: 2,
c: {
key: value
// ~~ 'foo' 속성이 'Foo' νƒ€μž…μ— ν•„μš”ν•˜μ§€λ§Œ 'Bar' νƒ€μž…μ—λŠ” μ—†μŠ΅λ‹ˆλ‹€.
}
};

λ‹¨μˆœνžˆ μƒκ°ν•˜λ©΄ config 객체 전체λ₯Ό as any둜 μ„ μ–Έν•΄μ„œ 였λ₯˜λ₯Ό μ œκ±°ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

const config: Config = {
a: 1,
b: 2,
c: {
key: value
}
} as any; // μ΄λ ‡κ²Œ ν•˜μ§€ λ§™μ‹œλ‹€!

객체 전체λ₯Ό any둜 λ‹¨μ–Έν•˜λ©΄ λ‹€λ₯Έ 속성듀 μ—­μ‹œ νƒ€μž… 체크가 λ˜μ§€ μ•ŠλŠ” λΆ€μž‘μš©μ΄ μƒκΉλ‹ˆλ‹€. κ·ΈλŸ¬λ―€λ‘œ λ‹€μŒ μ½”λ“œμ²˜λŸΌ μ΅œμ†Œν•œμ˜ λ²”μœ„μ—μ„œλ§Œ anyλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

const config: Config = {
a: 1,
b: 2,
c: {
key: value as any
}
};

πŸ₯• μ•„μ΄ν…œ 39. anyλ₯Ό ꡬ체적으둜 λ³€ν˜•ν•΄μ„œ μ‚¬μš©ν•˜κΈ°β€‹

anyλŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ—μ„œ ν‘œν˜„ν•  수 μžˆλŠ” λͺ¨λ“  값을 μ•„μš°λ₯΄λŠ” 맀우 큰 λ²”μœ„μ˜ νƒ€μž…μž…λ‹ˆλ‹€. any νƒ€μž…μ—λŠ” λͺ¨λ“  숫자, λ¬Έμžμ—΄, λ°°μ—΄, 객체, μ •κ·œμ‹, ν•¨μˆ˜, 클래슀, DOM μ—˜λ¦¬λ¨ΌνŠΈλŠ” λ¬Όλ‘  nullκ³Ό undefinedκΉŒμ§€λ„ ν¬ν•¨λ©λ‹ˆλ‹€.
λ°˜λŒ€λ‘œ λ§ν•˜λ©΄, 일반적인 μƒν™©μ—μ„œλŠ” any보닀 더 ꡬ체적으둜 ν‘œν˜„ν•  수 μžˆλŠ” νƒ€μž…μ΄ μ‘΄μž¬ν•  κ°€λŠ₯성이 λ†’κΈ° λ•Œλ¬Έμ— 더 ꡬ체적인 νƒ€μž…μ„ μ°Ύμ•„ νƒ€μž… μ•ˆμ „μ„±μ„ 높이도둝 ν•΄μ•Ό ν•©λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄, any νƒ€μž…μ˜ 값을 κ·ΈλŒ€λ‘œ μ •κ·œμ‹μ΄λ‚˜ ν•¨μˆ˜μ— λ„£λŠ” 것은 ꢌμž₯λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

function getLengthBad(array: any) { // μ΄λ ‡κ²Œ ν•˜μ§€ λ§™μ‹œλ‹€!
return array.length;
}

function getLength(array: any[]) {
return array:length;
}

μ•žμ˜ μ˜ˆμ œμ—μ„œ anyλ₯Ό μ‚¬μš©ν•˜λŠ” getLengthBadλ³΄λ‹€λŠ” any[]λ₯Ό μ‚¬μš©ν•˜λŠ” getLengthκ°€ 더 쒋은 ν•¨μˆ˜μž…λ‹ˆλ‹€. κ·Έ μ΄μœ λŠ” μ„Έ κ°€μ§€μž…λ‹ˆλ‹€.

  • ν•¨μˆ˜ λ‚΄μ˜ array.length νƒ€μž…μ΄ μ²΄ν¬λ©λ‹ˆλ‹€.
  • ν•¨μˆ˜μ˜ λ°˜ν™˜ νƒ€μž…μ΄ any λŒ€μ‹  number둜 μΆ”λ‘ λ©λ‹ˆλ‹€.
  • ν•¨μˆ˜ 호좜될 λ•Œ λ§€κ°œλ³€μˆ˜κ°€ 배열인지 μ²΄ν¬ν•©λ‹ˆλ‹€.

그리고 ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜κ°€ 객체이긴 ν•˜μ§€λ§Œ 값을 μ•Œ 수 μ—†λ‹€λ©΄ {[key: string]: any}처럼 μ„ μ–Έν•˜λ©΄ λ©λ‹ˆλ‹€.

function hasTwelveLetterKey(o: {[key: string]: any}) {
for (const key in o) {
if (key.length === 12) {
return true;
}
}
return false;
}

μ•žμ˜ 예제처럼 ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜κ°€ κ°μ²΄μ§€λ§Œ 값을 μ•Œ 수 μ—†λ‹€λ©΄ λͺ¨λ“  λΉ„κΈ°λ³Έν˜• νƒ€μž…μ„ ν¬ν•¨ν•˜λŠ” object νƒ€μž…μ„ μ‚¬μš©ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€. objectνƒ€μž…μ€ 객체의 ν‚€λ₯Ό μ—΄κ±°ν•  μˆ˜λŠ” μžˆμ§€λ§Œ 속성에 μ ‘κ·Όν•  수 μ—†λ‹€λŠ” μ μ—μ„œ {[key: string]: any}와 μ•½κ°„ λ‹€λ¦…λ‹ˆλ‹€.

ν•¨μˆ˜μ˜ νƒ€μž…μ—μ„œλ„ λ‹¨μˆœνžˆ anyλ₯Ό μ‚¬μš©ν•΄μ„œλŠ” μ•ˆ λ©λ‹ˆλ‹€. μ΅œμ†Œν•œμœΌλ‘œλ‚˜λ§ˆ ꡬ체화할 수 μžˆλŠ” μ„Έ 가지 방법이 μžˆμŠ΅λ‹ˆλ‹€.

type Fn0 = () => any; // λ§€κ°œλ³€μˆ˜ 없이 호좜 κ°€λŠ₯ν•œ λͺ¨λ“  ν•¨μˆ˜
type Fn1 = (arg: any) => any; // λ§€κ°œλ³€μˆ˜ 1개
type FnN = (...args: any[]) => any; // λͺ¨λ“  개수의 λ§€κ°œλ³€μˆ˜ "Function" νƒ€μž…κ³Ό λ™μΌν•©λ‹ˆλ‹€.

μ•žμ˜ μ˜ˆμ œμ— λ“±μž₯ν•œ μ„Έ 가지 ν•¨μˆ˜ νƒ€μž… λͺ¨λ‘ anyλ³΄λ‹€λŠ” κ΅¬μ²΄μ μž…λ‹ˆλ‹€. λ§ˆμ§€λ§‰ 쀄을 잘 μ‚΄νŽ΄λ³΄λ©΄ ...args의 νƒ€μž…μ„ any[]둜 μ„ μ–Έν–ˆμŠ΅λ‹ˆλ‹€. any둜 선언해도 λ™μž‘ν•˜μ§€λ§Œ any[]둜 μ„ μ–Έν•˜λ©΄ λ°°μ—΄ ν˜•νƒœγ…λΌλŠ” 것을 μ•Œ 수 μžˆμ–΄ 더 κ΅¬μ²΄μ μž…λ‹ˆλ‹€.

const numArgsBad = (...args: any) => args.length; // anyλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.
const numArgsGood = (...args: any[]) => args.length; // numberλ₯Ό λ°˜ν™˜ν•©λ‹ˆλ‹€.

πŸ₯• μ•„μ΄ν…œ 40. ν•¨μˆ˜ μ•ˆμœΌλ‘œ νƒ€μž… 단언문 감좔기​

ν•¨μˆ˜ λ‚΄λΆ€μ—λŠ” νƒ€μž… 단언을 μ‚¬μš©ν•˜κ³  ν•¨μˆ˜ μ™ΈλΆ€λ‘œ λ“œλŸ¬λ‚˜λŠ” νƒ€μž… μ •μ˜λ₯Ό μ •ν™•νžˆ λͺ…μ‹œν•˜λŠ” μ •λ„λ‘œ λλ‚΄λŠ” 게 λ‚«μŠ΅λ‹ˆλ‹€. ν”„λ‘œμ νŠΈ μ „λ°˜μ— μœ„ν—˜ν•œ νƒ€μž… 단언문이 λ“œλŸ¬λ‚˜ μžˆλŠ” 것보닀, μ œλŒ€λ‘œ νƒ€μž…μ΄ μ •μ˜λœ ν•¨μˆ˜ μ•ˆμœΌλ‘œ νƒ€μž… 단언문을 κ°μΆ”λŠ” 것이 더 쒋은 μ„€κ³„μž…λ‹ˆλ‹€.

예λ₯Ό λ“€μ–΄, μ–΄λ–€ ν•¨μˆ˜κ°€ μžμ‹ μ˜ λ§ˆμ§€λ§‰ ν˜ΈμΆœμ„ μΊμ‹œν•˜λ„λ‘ λ§Œλ“ λ‹€κ³  κ°€μ •ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

declare function cacheLast<T extends Function>(fn: T): T;

declare function shallowEqual(a: any, b: any): boolean;
function cacheLast<T extends Function>(fn: T): T {
let lastArgs: any[]|null = null;
let lastResult: any;

return function(...args: any[]) {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
// '(...args: any[]) => any' ν˜•μ‹μ€ 'T' ν˜•μ‹μ— ν• λ‹Ήν•  수 μ—†μŠ΅λ‹ˆλ‹€.
if (!lastArgs || !shallowEqual(lastArgs, args)) {
lastResult = fn(...args);
lastArgs = args;
}

return lastResult;
};
}

νƒ€μž…μŠ€ν¬λ¦½νŠΈλŠ” λ°˜ν™˜λ¬Έμ— μžˆλŠ” ν•¨μˆ˜μ™€ 원본 ν•¨μˆ˜ Tνƒ€μž…μ΄ μ–΄λ–€ 관련이 μžˆλŠ”μ§€ μ•Œμ§€ λͺ»ν•˜κΈ° λ•Œλ¬Έμ— 였λ₯˜κ°€ λ°œμƒν–ˆμŠ΅λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ 결과적으둜 원본 ν•¨μˆ˜ T νƒ€μž…κ³Ό λ™μΌν•œ λ§€κ°œλ³€μˆ˜λ‘œ 호좜되고 λ°˜ν™˜κ°’ μ—­μ‹œ μ˜ˆμƒν•œ κ²°κ³Όκ°€ 되기 λ•Œλ¬Έμ—, νƒ€μž… 단언문을 μΆ”κ°€ν•΄μ„œ 였λ₯˜λ₯Ό μ œκ±°ν•˜λŠ” 것이 큰 λ¬Έμ œκ°€ λ˜μ§€λŠ” μ•ŠμŠ΅λ‹ˆλ‹€.

function cacheLast<T extends Function>(fn: T): T {
let lastArgs: any[]|null = null;
let lastResult: any;

return function(...args: any[]) {
if (!lastArgs || !shallowEqual(lastArgs, args)) {
lastResult = fn(...args);
lastArgs = args;
}

return lastResult;
} as unknown as T;
}

μ‹€μ œλ‘œ ν•¨μˆ˜λ₯Ό μ‹€ν–‰ν•΄ 보면 잘 λ™μž‘ν•©λ‹ˆλ‹€.

declare function shallowObjectEqual<T extends object>(a: T, b: T): boolean;
declare function shallowEqual(a: any, b: any): boolean;
function shallowObjectEqual<T extends object>(a: T, b: T): boolean {
for (const [k, aVal] of Object.entries(a)) {
if (!(k in b) || aVal !== b[k]) { // '{}' ν˜•μ‹μ— 인덱슀 μ‹œκ·Έλ‹ˆμ²˜κ°€ μ—†μœΌλ―€λ‘œ μš”μ†Œμ— μ•”μ‹œμ μœΌλ‘œ 'any' ν˜•μ‹μ΄ μžˆμŠ΅λ‹ˆλ‹€.
return false;
}
}
return Object.keys(a).length === Object.keys(b).length;
}

if ꡬ문의 k in b 체크둜 b 객체에 k속성이 μžˆλ‹€λŠ” 것을 ν™•μΈν–ˆμ§€λ§Œ b[k] λΆ€λΆ„μ—μ„œ 였λ₯˜κ°€ λ°œμƒν•˜λŠ” 것이 μ΄μƒν•©λ‹ˆλ‹€. μ–΄μ¨Œλ“  μ‹€μ œ 였λ₯˜κ°€ μ•„λ‹ˆλΌλŠ” 것을 μ•Œκ³  있기 λ•Œλ¬Έμ— any둜 λ‹¨μ–Έν•˜λŠ” μˆ˜λ°–μ— μ—†μŠ΅λ‹ˆλ‹€.

function shallowObjectEqual<T extends object>(a: T, b: T): boolean {
for (const [k, aVal] of Object.entries(a)) {
if (!(k in b) || aVal !== (b as any)[k]) {
return false;
}
}
return Object.keys(a).length === Object.keys(b).length;
}

b as any νƒ€μž… 단언문은 μ•ˆμ „ν•˜λ©°(k in b 체크λ₯Ό ν–ˆμœΌλ―€λ‘œ), κ²°κ΅­ μ •ν™•ν•œ νƒ€μž…μœΌλ‘œ μ •μ˜λ˜κ³  μ œλŒ€λ‘œ κ΅¬ν˜„λœ ν•¨μˆ˜κ°€ λ©λ‹ˆλ‹€. 객체가 같은지 μ²΄ν¬ν•˜κΈ° μœ„ν•΄ 객체 μˆœνšŒμ™€ 단언문이 μ½”λ“œμ— 직접 λ“€μ–΄κ°€λŠ” 것보닀, μ•žμ˜ μ½”λ“œμ²˜λŸΌ λ³„λ„μ˜ ν•¨μˆ˜λ‘œ 뢄리해 λ‚΄λŠ” 것이 훨씬 쒋은 μ„€κ³„μž…λ‹ˆλ‹€.

πŸ₯• μ•„μ΄ν…œ 41. any의 진화λ₯Ό μ΄ν•΄ν•˜κΈ°β€‹

function range(start: number, limit: number) {
const out = []; // νƒ€μž…μ΄ any[]
for (let i = start; i < limit; i++) {
out.push(i); // out의 νƒ€μž…μ΄ any[]
}
return out; // λ°˜ν™˜ νƒ€μž…μ΄ number[]둜 좔둠됨.
}

out의 νƒ€μž…μ€ any[]둜 μ„ μ–Έλ˜μ—ˆμ§€λ§Œ number νƒ€μž…μ˜ 값을 λ„£λŠ” μˆœκ°„λΆ€ν„° νƒ€μž…μ€ number[]둜 μ§„ν™”ν•©λ‹ˆλ‹€.
νƒ€μž…μ˜ μ§„ν™”λŠ” νƒ€μž… 쒁히기(μ•„μ΄ν…œ 22)와 λ‹€λ¦…λ‹ˆλ‹€. 배열에 λ‹€μ–‘ν•œ νƒ€μž…μ˜ μš”μ†Œλ₯Ό λ„£μœΌλ©΄ λ°°μ—΄μ˜ νƒ€μž…μ΄ ν™•μž₯되며 μ§„ν™”ν•©λ‹ˆλ‹€.

const result = []; // νƒ€μž…μ΄ any[]
result.push('a');
result // νƒ€μž…μ΄ string[]
result.push(1);
result // νƒ€μž…μ΄ (string | number)[]

λ˜ν•œ μ‘°κ±΄λ¬Έμ—μ„œλŠ” 뢄기에 따라 νƒ€μž…μ΄ λ³€ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

let val; // νƒ€μž…μ΄ any
if (Math.random() < 0.5) {
val = /hello/;
val // νƒ€μž…μ΄ ReqExp
} else {
val = 12;
val // νƒ€μž…μ΄ number
}
val // νƒ€μž…μ΄ number | RegExp

λ³€μˆ˜μ˜ μ΄ˆκΉƒκ°’μ΄ null인 κ²½μš°μ—λ„ any의 진화가 μΌμ–΄λ‚©λ‹ˆλ‹€. 보톡은 try/catch 블둝 μ•ˆμ—μ„œ λ³€μˆ˜λ₯Ό ν• λ‹Ήν•˜λŠ” κ²½μš°μ— λ‚˜νƒ€λ‚©λ‹ˆλ‹€.

let val = null // νƒ€μž…μ΄ any
try {
somethingDangerous()
val = 12;
val // νƒ€μž…μ΄ number
} catch (e) {
console.log('alas!');
}
val // νƒ€μž…μ΄ number | null

any νƒ€μž…μ˜ μ§„ν™”λŠ” noImplicitAnyκ°€ μ„€μ •λœ μƒνƒœμ—μ„œ λ³€μˆ˜μ˜ νƒ€μž…μ΄ μ•”μ‹œμ  any인 κ²½μš°μ—λ§Œ μΌμ–΄λ‚©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λͺ…μ‹œμ μœΌλ‘œ anyλ₯Ό μ„ μ–Έν•˜λ©΄ νƒ€μž…μ΄ κ·ΈλŒ€λ‘œ μœ μ§€λ©λ‹ˆλ‹€.

anyκ°€ μ§„ν™”ν•˜λŠ” 방식은 일반적인 λ³€μˆ˜κ°€ μΆ”λ‘ λ˜λŠ” 원리와 λ™μΌν•©λ‹ˆλ‹€. 예λ₯Ό λ“€μ–΄, μ§„ν™”ν•œ λ°°μ—΄μ˜ νƒ€μž…μ΄ (string|number)[]라면, μ›λž˜ number[] νƒ€μž…μ΄μ–΄μ•Όν•˜μ§€λ§Œ μ‹€μˆ˜λ‘œ string이 μ„žμ—¬μ„œ 잘λͺ» μ§„ν™”ν•œ 것일 수 μžˆμŠ΅λ‹ˆλ‹€. νƒ€μž…μ„ μ•ˆμ „ν•˜κ²Œ 지킀기 μœ„ν•΄μ„œλŠ” μ•”μ‹œμ  anyλ₯Ό μ§„ν™”μ‹œν‚€λŠ” 방법보닀 λͺ…μ‹œμ  νƒ€μž… ꡬ문을 μ‹œμš©ν•˜λŠ” 것이 더 쒋은 μ„€κ³„μž…λ‹ˆλ‹€.

πŸ₯• μ•„μ΄ν…œ 42. λͺ¨λ₯΄λŠ” νƒ€μž…μ˜ κ°’μ—λŠ” any λŒ€μ‹  unknown을 μ‚¬μš©ν•˜κΈ°β€‹

λ¨Όμ € ν•¨μˆ˜μ˜ λ°˜ν™˜κ°’κ³Ό κ΄€λ ¨λœ unknown을 μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€.

function parseYAML(yaml: string): any {
// ...
}

ν•¨μˆ˜μ—μ„œ λ°˜ν™˜ νƒ€μž…μœΌλ‘œ anyλ₯Ό μ‚¬μš©ν•˜λŠ” 것은 쒋지 μ•Šμ€ μ„€κ³„μž…λ‹ˆλ‹€.
λŒ€μ‹  parseYAMLλ₯Ό ν˜ΈμΆœν•œ κ³³μ—μ„œ λ°˜ν™˜κ°’μ„ μ›ν•˜λŠ” νƒ€μž…μœΌλ‘œ ν• λ‹Ήν•˜λŠ” 것이 μ΄μƒμ μž…λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ ν•¨μˆ˜μ˜ λ°˜ν™˜κ°’μ— νƒ€μž… 선언을 κ°•μ œν•  수 μ—†κΈ° λ•Œλ¬Έμ—, ν˜ΈμΆœν•œ κ³³μ—μ„œ νƒ€μž… 선언을 μƒλž΅ν•˜κ²Œ 되면 μ‚¬μš©λ˜λŠ” κ³³λ§ˆλ‹€ νƒ€μž… 였λ₯˜κ°€ λ°œμƒν•˜κ²Œ λ©λ‹ˆλ‹€.

const book = parseYAML(`
name: Jane Eyre
author: Charlotte Bronte
`);

alert(book.title); // 였λ₯˜ μ—†μŒ, λŸ°νƒ€μž„μ— "undefined" κ²½κ³ 
book('read'); // 였λ₯˜ μ—†μŒ, λŸ°νƒ€μž„μ— "TypeError: book은 ν•¨μˆ˜κ°€ μ•„λ‹™λ‹ˆλ‹€" μ˜ˆμ™Έ λ°œμƒ

λŒ€μ‹  parseYAML이 unknown νƒ€μž…μ„ λ°˜ν™˜ν•˜κ²Œ λ§Œλ“œλŠ” 것이 더 μ•ˆμ „ν•©λ‹ˆλ‹€.

function safeParseYAML(yaml: string): unknown {
return parseYAML(yaml);
}

const book = safeParseYAML(`
name: The Tenant of Wildfell Hall
author: Anne Brnote
`);

alert(book.title); // κ°œμ²΄κ°€ 'unknown' ν˜•μ‹μž…λ‹ˆλ‹€.
book('read'); // 객체가 'unknown' ν˜•μ‹μž…λ‹ˆλ‹€.

unknown νƒ€μž…μ„ μ΄ν•΄ν•˜κΈ° μœ„ν•΄μ„œλŠ” ν• λ‹Ή κ°€λŠ₯μ„±μ˜ κ΄€μ μ—μ„œ anyλ₯Ό 생각해 λ³Ό ν•„μš”κ°€ μžˆμŠ΅λ‹ˆλ‹€. anyκ°€ κ°•λ ₯ν•˜λ©΄μ„œλ„ μœ„ν—˜ν•œ μ΄μœ λŠ” λ‹€μŒ 두 가지 νŠΉμ§•μœΌλ‘œλΆ€ν„° λΉ„λ‘―λ©λ‹ˆλ‹€.

  • μ–΄λ– ν•œ νƒ€μž…μ΄λ“  anyνƒ€μž…μ— ν• λ‹Ή κ°€λŠ₯ν•˜λ‹€.
  • any νƒ€μž…μ€ μ–΄λ– ν•œ νƒ€μž…μœΌλ‘œλ„ ν• λ‹Ή κ°€λŠ₯ν•˜λ‹€. (never νƒ€μž…μ€ μ œμ™Έ)

νƒ€μž… μ²΄μ»€λŠ” 집합 기반이기 λ•Œλ¬Έμ— anyλ₯Ό μ‚¬μš©ν•˜λ©΄ νƒ€μž… 체컀가 λ¬΄μš©μ§€λ¬Όμ΄ λœλ‹€λŠ” 것을 μ€‘μ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.

unknown은 any λŒ€μ‹  μ“Έ 수 μžˆλŠ” νƒ€μž… μ‹œμŠ€ν…œμ— λΆ€ν•©ν•˜λŠ” νƒ€μž…μž…λ‹ˆλ‹€. unknown νƒ€μž…μ€ μ•žμ—μ„œ μ–ΈκΈ‰ν•œ any의 첫 번째 속성을 λ§Œμ‘±ν•˜μ§€λ§Œ, 두 번째 속성(unknown은 였직 unknownκ³Ό anyμ—λ§Œ ν• λ‹Ή κ°€λŠ₯)은 λ§Œμ‘±ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 반면 never νƒ€μž…μ€ unknownκ³Ό μ •λ°˜λŒ€μž…λ‹ˆλ‹€.
첫 번째 속성(μ–΄λ–€ νƒ€μž…λ„ never에 ν• λ‹Ήν•  수 μ—†μŒ)은 λ§Œμ‘±ν•˜μ§€ μ•Šμ§€λ§Œ, 두 번째 속성(μ–΄λ– ν•œ νƒ€μž…μœΌλ‘œλ„ ν• λ‹Ή κ°€λŠ₯)은 λ§Œμ‘±ν•©λ‹ˆλ‹€.

unknown νƒ€μž…μΈ μ±„λ‘œ 값을 μ‚¬μš©ν•˜λ©΄ 였λ₯˜κ°€ λ°œμƒν•©λ‹ˆλ‹€. unknown인 값에 ν•¨μˆ˜ ν˜ΈμΆœμ„ ν•˜κ±°λ‚˜ 연산을 ν•˜λ €κ³  해도 λ§ˆμ°¬κ°€μ§€μž…λ‹ˆλ‹€. unknown μƒνƒœλ‘œ μ‚¬μš©ν•˜λ €κ³  ν•˜λ©΄ 였λ₯˜κ°€ λ°œμƒν•˜κΈ° λ•Œλ¬Έμ—, μ μ ˆν•œ νƒ€μž…μœΌλ‘œ λ³€ν™˜ν•˜λ„λ‘ κ°•μ œν•  수 μžˆμŠ΅λ‹ˆλ‹€.

const book = safeParseYAML(`
name: The Tenant of Wildfell Hall
author: Anne Brnote
`) as Book;

alert(book.title); // 'Book' ν˜•μ‹μ— 'title' 속성이 μ—†μŠ΅λ‹ˆλ‹€.
book('read'); // 이 식은 ν˜ΈμΆœν•  수 μ—†μŠ΅λ‹ˆλ‹€.

ν•¨μˆ˜μ˜ λ°˜ν™˜ νƒ€μž…μΈ unknown κ·ΈλŒ€λ‘œ 값을 μ‚¬μš©ν•  수 μ—†κΈ° λ•Œλ¬Έμ— Book으둜 νƒ€μž… 단언을 ν•΄μ•Ό ν•©λ‹ˆλ‹€. μ• μ΄ˆμ— λ°˜ν™˜κ°’μ„ Book이라고 κΈ°λŒ€ν•˜λ©° ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜κΈ° λ•Œλ¬Έμ— 단언문은 λ¬Έμ œκ°€ λ˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. 그리고 Book νƒ€μž… κΈ°μ€€μœΌλ‘œ νƒ€μž… 체크가 되기 λ•Œλ¬Έμ—, unknown νƒ€μž… κΈ°μ€€μœΌλ‘œ 였λ₯˜λ₯Ό ν‘œμ‹œν–ˆλ˜ μ˜ˆμ œλ³΄λ‹€ 였λ₯˜ 정보가 더 μ •ν™•ν•©λ‹ˆλ‹€.

λ‹€μŒμœΌλ‘œ λ³€μˆ˜ μ„ μ–Έκ³Ό κ΄€λ ¨λœ unknown을 μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€. μ–΄λ– ν•œ 값이 μžˆμ§€λ§Œ κ·Έ νƒ€μž…μ„ λͺ¨λ₯΄λŠ” κ²½μš°μ— unknown을 μ‚¬μš©ν•©λ‹ˆλ‹€.

interface Feature {
id?: string | number;
geometry: Geometry;
properties: unknown; // JSON 직렬화가 κ°€λŠ₯ν•œ λͺ¨λ“  것을 λ‹΄λŠ” μž‘λ™μ‚¬λ‹ˆ μ£Όλ¨Έλ‹ˆ 같은 쑴재둜 μ˜ˆμƒν•  수 μ—†κΈ° λ•Œλ¬Έμ— unknown μ‚¬μš©
}

νƒ€μž… 단언문에 unknownμ—μ„œ μ›ν•˜λŠ” νƒ€μž…μœΌλ‘œ λ³€ν™˜ν•˜λŠ” μœ μΌν•œ 방법은 μ•„λ‹™λ‹ˆλ‹€. instanceofλ₯Ό μ²΄ν¬ν•œ ν›„ unknownμ—μ„œ μ›ν•˜λŠ” νƒ€μž…μœΌλ‘œ λ³€ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

function processValue(val: unknown) {
if (val instanceof Date) {
val // νƒ€μž…μ΄ Date
}
}

λ˜ν•œ μ‚¬μš©μž μ •μ˜ νƒ€μž… κ°€λ“œλ„ unknownμ—μ„œ μ›ν•˜λŠ” νƒ€μž…μœΌλ‘œ λ³€ν™˜ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

function isBook(val: unknown): val is Book {
return (
typeof(val) === 'object' && val !== null && 'name' in val && 'author' in val
);
}

function processValue(val: unkown) {
if (isBook(val)) {
val; // νƒ€μž…μ΄ Book
}
}

가끔 unknown λŒ€μ‹  μ œλ„ˆλ¦­ λ§€κ°œλ³€μˆ˜κ°€ μ‚¬μš©λ˜λŠ” κ²½μš°λ„ μžˆμŠ΅λ‹ˆλ‹€. μ œλ„ˆλ¦­μ„ μ‚¬μš©ν•˜κΈ° μœ„ν•΄ λ‹€μŒ μ½”λ“œμ²˜λŸΌ safeParseYAML ν•¨μˆ˜λ₯Ό μ„ μ–Έν•  수 μžˆμŠ΅λ‹ˆλ‹€.

function safeParseYAML<T>(yaml: string): T {
return parsYAML(yaml);
}

κ·ΈλŸ¬λ‚˜ μ•žμ˜ μ½”λ“œλŠ” 일반적으둜 νƒ€μž…μŠ€ν¬λ¦½νŠΈμ—μ„œ 쒋지 μ•Šμ€ μŠ€νƒ€μΌμž…λ‹ˆλ‹€.
μ œλ„ˆλ¦­μ„ μ‚¬μš©ν•œ μŠ€νƒ€μΌμ€ νƒ€μž… 단언문과 달라 λ³΄μ΄μ§€λ§Œ κΈ°λŠ₯μ μœΌλ‘œλŠ” λ™μΌν•©λ‹ˆλ‹€. μ œλ„ˆλ¦­λ³΄λ‹€λŠ” unknown을 λ°˜ν™˜ν•˜κ³  μ‚¬μš©μžκ°€ 직접 단언문을 μ‚¬μš©ν•˜κ±°λ‚˜ μ›ν•˜λŠ” λŒ€λ‘œ νƒ€μž…μ„ μ’νžˆλ„λ‘ κ°•μ œν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

λ‹€μŒμœΌλ‘œ 단언문과 κ΄€λ ¨λœ unknown을 μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€. 이쀑 λ‹¨μ–Έλ¬Έμ—μ„œ any λŒ€μ‹  unknown을 μ‚¬μš©ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

declare const foo: Foo;
let barAny = foo as any as Bar;
let barUnk = foo as unknown as Bar;

barAny와 barUnkλŠ” κΈ°λŠ₯적으둜 λ™μΌν•˜μ§€λ§Œ, λ‚˜μ€‘μ— 두 개의 단언문을 λΆ„λ¦¬ν•˜λŠ” λ¦¬νŒ©ν„°λ§μ„ ν•œλ‹€λ©΄ unknown ν˜•νƒœκ°€ 더 μ•ˆμ „ν•©λ‹ˆλ‹€. any의 κ²½μš°μ—λŠ” λΆ„λ¦¬λ˜λŠ” μˆœκ°„ κ·Έ 영ν–₯λ ₯이 μ „μ—Όλ³‘μ²˜λŸΌ νΌμ§€κ²Œ λ©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ unknown의 κ²½μš°λŠ” λΆ„λ¦¬λ˜λŠ” μ¦‰μ‹œ 였λ₯˜λ₯Ό λ°œμƒν•˜κ²Œ λ˜λ―€λ‘œ 더 μ•ˆμ „ν•©λ‹ˆλ‹€.

λ§ˆμ§€λ§‰μœΌλ‘œ unknownκ³Ό μœ μ‚¬ν•˜μ§€λ§Œ 쑰금 λ‹€λ₯Έ νƒ€μž…λ“€λ„ μ•Œμ•„λ³΄κ² μŠ΅λ‹ˆλ‹€. object λ˜λŠ” {}λ₯Ό μ‚¬μš©ν•˜λŠ” 방법 μ—­μ‹œ unknown만큼 λ²”μœ„κ°€ 넓은 νƒ€μž…μ΄μ§€λ§Œ, unknownλ³΄λ‹€λŠ” λ²”μœ„κ°€ μ•½κ°„ μ’μŠ΅λ‹ˆλ‹€.

  • {} νƒ€μž…μ€ nullκ³Ό undefinedλ₯Ό μ œμ™Έν•œ λͺ¨λ“  값을 ν¬ν•¨ν•©λ‹ˆλ‹€.
  • object νƒ€μž…μ€ λͺ¨λ“  λΉ„κΈ°λ³Έν˜• νƒ€μž…μœΌλ‘œ μ΄λ£¨μ–΄μ§‘λ‹ˆλ‹€. μ—¬κΈ°μ—λŠ” true λ˜λŠ” 12 λ˜λŠ” "foo"κ°€ ν¬ν•¨λ˜μ§€ μ•Šμ§€λ§Œ 객체와 배열은 ν¬ν•¨λ©λ‹ˆλ‹€.

unknown νƒ€μž…μ΄ λ„μž…λ˜κΈ° μ „μ—λŠ” {}κ°€ 더 일반적으둜 μ‚¬μš©λ˜μ—ˆμ§€λ§Œ, μ΅œκ·Όμ—λŠ” {}λ₯Ό μ‚¬μš©ν•˜λŠ” κ²½μš°κ°€ κ½€ λ“œλ­…λ‹ˆλ‹€. μ •λ§λ‘œ nullκ³Ό undefinedκ°€ λΆˆκ°€λŠ₯ν•˜λ‹€κ³  νŒλ‹¨λ˜λŠ” κ²½μš°μ—λ§Œ unknown λŒ€μ‹  {}λ₯Ό μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.

πŸ₯• μ•„μ΄ν…œ 43. λͺ½ν‚€ νŒ¨μΉ˜λ³΄λ‹€λŠ” μ•ˆμ „ν•œ νƒ€μž…μ„ μ‚¬μš©ν•˜κΈ°β€‹

μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ κ°€μž₯ 유λͺ…ν•œ νŠΉμ§• 쀑 ν•˜λ‚˜λŠ”, 객체와 ν΄λž˜μŠ€μ— μž„μ˜μ˜ 속성을 μΆ”κ°€ν•  수 μžˆμ„ 만큼 μœ μ—°ν•˜λ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

window.monkey = 'Tamarin';
document.monkey = 'Howler';

μœ„ 예처럼 window λ˜λŠ” DOM λ…Έλ“œμ— 데이터λ₯Ό μΆ”κ°€ν•œλ‹€κ³  κ°€μ •ν•΄ λ³΄κ² μŠ΅λ‹ˆλ‹€. 그러면 κ·Έ λ°μ΄ν„°λŠ” 기본적으둜 μ „μ—­ λ³€μˆ˜κ°€ λ©λ‹ˆλ‹€. μ „μ—­ λ³€μˆ˜λ₯Ό μ‚¬μš©ν•˜λ©΄ 은연쀑에 ν”„λ‘œκ·Έλž¨ λ‚΄μ—μ„œ μ„œλ‘œ 멀리 떨어진 λΆ€λΆ„λ“€ 간에 μ˜μ‘΄μ„±μ„ λ§Œλ“€κ²Œ λ©λ‹ˆλ‹€.
νƒ€μž…μŠ€ν¬λ¦½νŠΈκΉŒμ§€ λ”ν•˜λ©΄ 또 λ‹€λ₯Έ λ¬Έμ œκ°€ λ°œμƒν•©λ‹ˆλ‹€. νƒ€μž… μ²΄μ»€λŠ” Document와 HTMLElement의 λ‚΄μž₯ 속성에 λŒ€ν•΄μ„œλŠ” μ•Œκ³  μžˆμ§€λ§Œ, μž„μ˜λ‘œ μΆ”κ°€ν•œ 속성에 λŒ€ν•΄μ„œλŠ” μ•Œμ§€ λͺ»ν•©λ‹ˆλ‹€.

document.monkey = 'Tamarin';
// ~~~~~~ 'Document' μœ ν˜•μ— 'monkey' 속성이 μ—†μŠ΅λ‹ˆλ‹€.

이 였λ₯˜λ₯Ό ν•΄κ²°ν•˜λŠ” κ°€μž₯ κ°„λ‹¨ν•œ 방법은 any 단언문을 μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

(document as any).monkey = 'Tamarin'; // 정상

ν•˜μ§€λ§Œ anyλ₯Ό μ‚¬μš©ν•¨μœΌλ‘œμ¨ νƒ€μž… μ•ˆμ „μ„±μ„ μƒμ‹€ν•˜κ³ , μ–Έμ–΄ μ„œλΉ„μŠ€λ₯Ό μ‚¬μš©ν•  수 μ—†κ²Œ λœλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

μ΅œμ„ μ˜ 해결책은 document λ˜λŠ” DOMμœΌλ‘œλΆ€ν„° 데이터λ₯Ό λΆ„λ¦¬ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.
뢄리할 수 μ—†λŠ” 경우, 두 κ°€μΉ˜ 차선책이 μ‘΄μž¬ν•©λ‹ˆλ‹€.

첫 번째, interface의 특수 κΈ°λŠ₯ 쀑 ν•˜λ‚˜μΈ 보강(augmentation)을 μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

interface Document {
// λͺ½ν‚€ 패치의 속(genus) λ˜λŠ” μ’…(species)
monkey: string;
}

document.monkey = 'Tamarin'; // 정상

보강을 μ‚¬μš©ν•œ 방법이 any보닀 λ‚˜μ€ 점은 λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.

  • νƒ€μž…μ΄ 더 μ•ˆμ „ν•©λ‹ˆλ‹€. νƒ€μž… μ²΄μ»€λŠ” μ˜€νƒ€λ‚˜ 잘λͺ»λœ νƒ€μž…μ˜ 할당을 였λ₯˜λ‘œ ν‘œμ‹œν•©λ‹ˆλ‹€.
  • 속성에 주석을 뢙일 수 μžˆμŠ΅λ‹ˆλ‹€.
  • 속성에 μžλ™μ™„μ„±μ„ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.
  • λͺ½ν‚€ νŒ¨μΉ˜κ°€ μ–΄λ–€ 뢀뢄에 μ μš©λ˜μ—ˆλŠ”μ§€ μ •ν™•ν•œ 기둝이 λ‚¨μŠ΅λ‹ˆλ‹€.

그리고 λͺ¨λ“ˆμ˜ κ΄€μ μ—μ„œ, μ œλŒ€λ‘œ λ™μž‘ν•˜κ²Œ ν•˜λ €λ©΄ global 선언을 μΆ”κ°€ν•΄μ•Ό ν•©λ‹ˆλ‹€.

export {};
declare global {
interface Document {
// λͺ½ν‚€ 패치의 속(genus) λ˜λŠ” μ’…(species)
monkey: string;
}
}

document.monkey = 'Tamarin'; // 정상

보강을 μ‚¬μš©ν•  λ•Œ μ£Όμ˜ν•΄μ•Ό ν•  점은 λͺ¨λ“ˆ μ˜μ—­κ³Ό 관련이 μžˆμŠ΅λ‹ˆλ‹€. 보강은 μ „μ—­μ μœΌλ‘œ 적용되기 λ•Œλ¬Έμ—, μ½”λ“œμ˜ λ‹€λ₯Έ λΆ€λΆ„μ΄λ‚˜ λΌμ΄λΈŒλŸ¬λ¦¬λ‘œλΆ€ν„° 뢄리할 수 μ—†μŠ΅λ‹ˆλ‹€. 그리고 μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ΄ μ‹€ν–‰λ˜λŠ” λ™μ•ˆ 속성을 ν• λ‹Ήν•˜λ©΄ μ‹€ν–‰ μ‹œμ μ—μ„œ 보강을 μ μš©ν•  방법이 μ—†μŠ΅λ‹ˆλ‹€.

두 번째, 더 ꡬ체적인 νƒ€μž… 단언문을 μ‚¬μš©ν•˜λŠ” κ²ƒμž…λ‹ˆλ‹€.

interface MonkeyDocument extends Document {
// λͺ½ν‚€ 패치의 속(genus) λ˜λŠ” μ’…(species)
monkey: string;
}
(document as MonkeyDocument).monkey = 'Macaque';

MonkeyDocumentλŠ” Documentλ₯Ό ν™•μž₯ν•˜κΈ° λ•Œλ¬Έμ— νƒ€μž… 단언문은 정상이며 ν• λ‹Ήλ¬Έμ˜ νƒ€μž…μ€ μ•ˆμ „ν•©λ‹ˆλ‹€. λ˜ν•œ Document νƒ€μž…μ„ κ±΄λ“œλ¦¬μ§€ μ•Šκ³  λ³„λ„λ‘œ ν™•μž₯ν•˜λŠ” μƒˆλ‘œμš΄ νƒ€μž…μ„ λ„μž…ν–ˆκΈ° λ•Œλ¬Έμ— λͺ¨λ“ˆ μ˜μ—­ λ¬Έμ œλ„ ν•΄κ²°ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ λͺ½ν‚€ 패치된 속성을 μ°Έμ‘°ν•˜λŠ” κ²½μš°μ—λ§Œ 단언문을 μ‚¬μš©ν•˜κ±°λ‚˜ μƒˆλ‘œμš΄ λ³€μˆ˜λ₯Ό λ„μž…ν•˜λ©΄ λ©λ‹ˆλ‹€. κ·ΈλŸ¬λ‚˜ λͺ½ν‚€νŒ¨μΉ˜λ₯Ό λ‚¨μš©ν•΄μ„œλŠ” μ•ˆ 되며 ꢁ극적으둜 더 잘 μ„€κ³„λœ ꡬ쑰둜 λ¦¬νŒ©ν„°λ§ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

πŸ₯• μ•„μ΄ν…œ 44. νƒ€μž… 컀버리지λ₯Ό μΆ”μ ν•˜μ—¬ νƒ€μž… μ•ˆμ „μ„± μœ μ§€ν•˜κΈ°β€‹

noImplicitAnyλ₯Ό μ„€μ •ν•˜κ³  λͺ¨λ“  μ•”μ‹œμ  any λŒ€μ‹  λͺ…μ‹œμ  νƒ€μž… ꡬ문을 좔가해도 any νƒ€μž…κ³Ό κ΄€λ ¨λœ λ¬Έμ œλ“€λ‘œλΆ€ν„° μ•ˆμ „ν•˜λ‹€κ³  ν•  수 μ—†μŠ΅λ‹ˆλ‹€. any νƒ€μž…μ€ μ—¬μ „νžˆ ν”„λ‘œκ·Έλž¨ 내에 μ‘΄μž¬ν•  수 μžˆλŠ” 두 가지 κ²½μš°κ°€ μžˆμŠ΅λ‹ˆλ‹€.

  • λͺ…μ‹œμ  any νƒ€μž… μ•„μ΄ν…œ 38κ³Ό μ•„μ΄ν…œ 39의 λ‚΄μš©μ— 따라 any νƒ€μž…μ˜ λ²”μœ„λ₯Ό 쒁히고 ꡬ체적으둜 λ§Œλ“€μ–΄λ„ μ—¬μ „νžˆ any νƒ€μž…μž…λ‹ˆλ‹€.

  • μ„œλ“œνŒŒν‹° νƒ€μž… μ„ μ–Έ 이 κ²½μš°μ—λŠ” @types μ„ μ–Έ νŒŒμΌλ‘œλΆ€ν„° any νƒ€μž…μ΄ μ „νŒŒλ˜κΈ° λ•Œλ¬Έμ— νŠΉλ³„νžˆ 쑰심해야 ν•©λ‹ˆλ‹€. noImplicitAnyλ₯Ό μ„€μ •ν•˜κ³  μ ˆλŒ€ anyλ₯Ό μ‚¬μš©ν•˜μ§€ μ•Šμ•˜λ‹€ ν•˜λ”λΌλ„ μ—¬μ „νžˆ any νƒ€μž…μ€ μ½”λ“œ μ „λ°˜μ— 영ν–₯을 λ―ΈμΉ©λ‹ˆλ‹€.

any νƒ€μž…μ€ νƒ€μž… μ•ˆμ „μ„±κ³Ό 생산성에 뢀정적인 영ν–₯을 λ―ΈμΉ  수 μžˆμœΌλ―€λ‘œ, ν”„λ‘œμ νŠΈμ—μ„œ any의 개수λ₯Ό μΆ”μ ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€. npm의 type-cover-age νŒ¨ν‚€μ§€λ₯Ό ν™œμš©ν•˜μ—¬ anyλ₯Ό 좔적할 수 μžˆλŠ” λͺ‡ 가지 방법이 μžˆμŠ΅λ‹ˆλ‹€.

$ npx type-coverage

μš”μ•½β€‹

  • noImplicitAnyκ°€ μ„€μ •λ˜μ–΄ μžˆμ–΄λ„, λͺ…μ‹œμ  any λ˜λŠ” μ„œλ“œνŒŒν‹° νƒ€μž… μ„ μ–Έ(@types)을 톡해 any νƒ€μž…μ€ μ½”λ“œ 내에 μ—¬μ „νžˆ μ‘΄μž¬ν•  수 μžˆλ‹€λŠ” 점을 μ£Όμ˜ν•΄μ•Ό ν•©λ‹ˆλ‹€.
  • μž‘μ„±ν•œ ν”„λ‘œκ·Έλž¨μ˜ νƒ€μž…μ΄ μ–Όλ§ˆλ‚˜ 잘 μ„ μ–Έλ˜μ—ˆλŠ”μ§€ 좔적해야 ν•©λ‹ˆλ‹€. μΆ”μ ν•¨μœΌλ‘œμ¨ any의 μ‚¬μš©μ„ 쀄여 λ‚˜κ°ˆ 수 있고 νƒ€μž… μ•ˆμ „μ„±μ„ κΎΈμ€€νžˆ 높일 수 μžˆμŠ΅λ‹ˆλ‹€.