34. 부정확한 타입보다는 미완성 타입을 사용하기
•
너무 과하게 타입을 지정하다보면 부정확한 타입지정으로 인해 사이드 이펙트가 발생해 정상적인 사용이 불가할 수 있습니다.
•
따라서 정확하게 모델링할 수 없다면, 차라리 any, unknown을 사용하는 편이 낫습니다.
35. 데이터가 아닌, API와 명세를 보고 타입 만들기
•
예시데이터가 아닌 명세서를 보고 만들어야만 정확한 타입을 지정할 수 있으니 주의합니다.
36. 해당 분야의 용어로 타입 이름 짓기
•
같은 의미의 다른 이름을 피하고, 최대한 해당 분야의 용어를 사용해야만 합니다.
37. 공싱 명칭에는 상표를 붙이기
•
구조적 타이핑으로인해 값을 세밀하게 구분할 수 없습니다. 따라서 세밀한 구분이 필요하다면 이를 명시해주는 것도 방법입니다.
type Meters = number & {_brand: 'meters'};
const meters = (m: number) => m as Meters;
const oneKim = meters(1000); // Meters
// 단 연산후 다시 number가 되기때문에 고려가 필요합니다.
const tenKim = oneKim * 10; // number
JavaScript
복사
5장 any 다루기
점진적인 마이그레이션 시 any는 중요한 역할을 합니다. 장단점을 체크하도록 합니다.
38. any 타입은 가능한 한 좁은 범위에서만 사용하기
•
최대한 영향을 적게 끼치는 방향으로 사용해야합니다.
•
1번과 같은 상황은 반환타입이 있을 때 함수 바깥(사용하는 측)까지 영향을 미치기 때문에 피해야 합니다.
// 1. X
function F1(){
const x: any = Foo();
process(x);
return x;
}
// 2. 개선
function F1(){
const x = Foo();
process(x as any);
return x;
}
JavaScript
복사
•
객체의 경우 필요한 부분에만 any를 사용해줘야합니다.
// 1. X
const config: Config = {
a : 1,
b: 2,
c : { key: value }
} as any;
// 2. 개선
const config: Config = {
a : 1,
b: 2,
c : { key: value as any }
};
JavaScript
복사
•
강제적으로 타입 오류제거시 @ts-ignore 또한 고려해볼 수 있습니다.
39. any를 구체적으로 변형해서 사용하기
•
배열
◦
any[]로 사용하기
•
객체
◦
{[key: string]: any}, Object 사용하기
◦
Object의 경우 객체 키를 열거할 수 있지만, 속성에 접근할 수 없습니다.
◦
o[key] // error 발생
•
함수
◦
type Fn0 = () ⇒ any;
◦
type Fn1 = (arg: any) ⇒ any;
◦
type FnN = (…args: any[]) ⇒ any; // Function 타입과 동일
40. 함수 안으로 타입 단언문 감추기
•
함수 내부가 너무 복잡하다면 외부로 드러나는 타입정의만 명시하는 것이 현실적인 해결책입니다.
function shallowObjectEqual<T extends object>(a: T, b: T): boolean {
for(copnst [k, oval] of Object.entries(a)){
if(!(k in b) || aVal !== (b as any)[k]) {
return false;
}
}
return Object.keys(a).length === Object.keys(b).length;
}
JavaScript
복사
41. any의 진화 이해하기
•
any로 선언된 변수등에 선언을 통해서 값이 진화할 수 있습니다.
function range(start: number, limit: number){
const out = [];
for(let i = start; i < limit; i++){
out.push(i);
}
return out; // number[]로 추론됨
}
JavaScript
복사
•
값이 null인 경우에도 일어나는데 주로 try, catch에서 발생합니다.
let val = null; // type: any
try {
somethingDangerous();
val = 12;
val // type: number
} catch(e) {
console.warn('e');
}
val // type: number | null
JavaScript
복사
•
단 noImplicityAny가 설정된 암시적 any인 경우에만 발생합니다. 명시적일경우 any가 유지됩니다.
let val: any; // type: any
try {
somethingDangerous();
val = 12;
val // type: any
} catch(e) {
console.warn('e');
}
val // type: any
JavaScript
복사
•
암시적 any의 경우 할당 없이 읽을 시 오류가 발생하며, 함수호출을 거쳐도 진화하지 않기때문에 여전히 에러가 발생합니다.
function makeSquares(start: number, limit: number){
const out = [];
range(start, limit).forEach(i => { out.push(i);});
return out; // any[]
}
JavaScript
복사
42. 모르는 타입의 값에 any 대신 unknown을 사용하기
•
any가 위험한 이유는 아래와 같습니다.
◦
어떠한 타입이든 any에 할당가능
◦
any는 어디에든 할당가능
•
unknown과 never는 조금 다릅니다.
◦
unknwon은 어떤 타입이든 할당가능하지만, unknown과 any에만 할당가능합니다.
◦
never는 어떤 타입도 할당할 수 없지만, 어디에든 할당가능합니다.
•
만약 반환값을 모른다면 unknown을 반환하고, 단언문을 통해 사용자가 타입을 좁히도록하는 강제하는 것이 좋습니다.
•
{}는 undefined와 null을 제외한 모든 값을 포함하고, object는 모든 비기본형 타입으로 이루어졌습니다.
43. 몽키 패치보다는 안전한 타입을 사용하기
•
document.monkey와 같이 객체에 값을 추가해주는건 위험하기에, 추가적인 선언이 필요합니다.
•
interface의 보강기능을 활용해줍니다.
interface Document {
monkey: string;
}
document.monkey = 'Tamarin';
JavaScript
복사
•
구체적인 타입 단언문을 사용해줍니다.
interface MonkeyDocument extends Document {
monkey: string;
}
(document as MonkeyDocument).monkey = 'Macaque';
JavaScript
복사
44. 타입 커버리지를 추적하여 타입 안전성 유지하기
•
noImplicityAny가 있더라도, 라이브러리등에 any가 있을 수 잇습니다.
•
type-coverage 패키지를 통해 추적 및 점검 가능합니다.