볞묞윌로 걎너뛰Ʞ

🐀 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의 사용을 쀄여 나갈 수 있고 타입 안전성을 ꟞쀀히 높음 수 있습니닀.