6장 타입 선언과 @types
45. devDependencies에 typescript와 @types 추가하기
•
dependencies : 런타임에 사용하는 코드
•
devDependencies : 개발 및 테스트에는 사용되지만, 런타임에는 필요없는 코드
•
peerDependencies : 실제로 패키지에서 직접 require(import)하지 않더라도 호환성이 필요한 경우 명시해줍니다. Library를 사용하는 사용자에게 버전을 맞춰야하는 것들을 명시해주고, 이에따라 warning이 뜨거나, 설치에서 에러가 발생합니다.
•
프로젝트 별로 다른 버전의 타입스크립트를 사용하므로, 시스템 레벨에 설치하면 안됩니다.
•
@types는 devDependencies에 추가해줘야 합니다.
46. 타입 선언과 관련된 세 가지 버전 이해하기
•
@types, 라이브러리 버전, ts 버전 3가지를 고려해야합니다.
•
라이브러리와 타입버전이 개별관리되는 방식은 4가지 문제가 있습니다.
◦
라이브러리 버전 > 타입 버전
▪
타입 선언을 업데이트 해줍니다.
▪
해당 사항이 아직 업데이트 되지 않았다면, 보강 기법을 활용하여, 에러가 발생하는 타입을 프로젝트 자체에 추가합니다.
◦
라이브러리 버전 < 타입 버전
▪
라이브러리를 올리거나, 타입을 내리기
◦
프로젝트 TS 버전 < 라이브러리 TS 버전
▪
버전을 조정해줍니다.
▪
declare module 선언으로 라이브러리의 타입 정보를 없애는 것도 방법입니다.
◦
@types 의존성이 라이브러리간에 충돌할 수 있습니다.
▪
npm ls @types/foo 를 통해서 타입 선언 중복 추척해 해결해줄 수 있습니다.
•
types: index.d.ts 와 같은 번들링에 타입선언을 포함하는 방식에는 4가지 문제점이 있습니다.
◦
타입버전을 따로 컨트롤할 수 없어 ts 버전이 올라가며 에러가 발생할 수 있습니다.
◦
보통 의존성은 devDependencies에 들어가는데 다른 사용자는 해당을 설치하지 않게되어 에러가 발생할 수 있습니다.
◦
프로젝트 과거 버전에 문제가 있는 경우 과거버전으로가서 패치 업데이트를 해야합니다.
◦
타입 선언의 패치업데이트를 자주하기 어렵습니다.
47. 공개 API에 등장하는 모든 타입을 익스포트하기
•
어차피 사용자가 필요하다면 타입 추출이 가능하므로, 숨기려드는 것을 필요없는 행동입니다.
48. API 주석에 TSDoc 사용하기
•
편집기가 처리해줘 JSDoc/TSDoc 사용이 좋습니다.
49. 콜백에서 this에 대한 타입 제공하기
class C {
vals = [1, 2, 3];
logSquares() {
for(const val of this.vals) {
console.log(val * val);
}
}
}
const c = new C();
c.logSquares();
// 1 4 9
const c = new C();
const method = c.logSquares;
method();
// Uncaught TypeError: Cannot read properties of undefined (reading 'vals')
JavaScript
복사
•
logSquares를 참조 변수로 사용하므로 this의 값은 undefined로 설정되어 에러가 발생합니다.
•
이를 해결하기 위해 call을 사용해서 해결할 수 있습니다.
•
이런 다양한 this의 문제가 발생할 수 있기 때문에 원리를 이해해야 하고, 콜백 함수에서 this 사용시 타입정보를 명시해줘야합니다.
50. 오버로딩 타입보다는 조건부 타입을 사용하기
function double(x) {
return x + x;
}
// 모호합니다.
function double(x: number|string): number|string;
// 과하게 구체적입니다.
// T를 'x'로 하게될 시 결과는 'xx'여야하는데 'x'라고 명시중입니다.
function double<T extends number|string>(x: T): T;
// 타입이 조금은 명확해졌습니다만 버그가 있습니다.
function double(x: number): number;
function double(x: string): string;
function f(x: number|string){
double(x); // 'string|number' 인수는 'string' 형식의 매개변수에 할당할 수 없습니다.
}
// 조건부 타입이 가장 좋은 해결책입니다.
function double<T extends number | string>(x: T): T extends string ? string : number;
JavaScript
복사
51. 의존성 분리를 위해 미러 타입 사용하기
•
@types/node속 Buffer와 같은 사용자에 따라 불필요한 경우 구조적 타이핑을 사용해주면 됩니다.
52. 테스팅 타입의 함정에 주의하기
•
타입을 테스트할 때는 함수 타입의 동일성과 할당 가능성의 차이점을 알고있어야합니다.
const lengths: number[] = map(['join', 'paul'], name => name.length);
JavaScript
복사
•
테스트를 위해 할당을 하는 방법에는 2가지 문제가 있습니다.
◦
불필요한 변수
◦
두 타입이 동일한지 체크하는 것이 아닌 할당 가능성만을 체크
▪
객체의 추가적인 속성 등을 체크하지 않고, 매개변수의 타입선언 갯수와 함수간 실제 사용의 일치를 고려하지 않습니다.
const double = (x: number) => x * 2;
assertType<(a: number, b: number) => number>(double); // 에러 x
JavaScript
복사
•
콜백이 있는 함수를 테스트 할때는 콜백 매개변수의 추론된 타입을 체크해야하고, thisrㅏ 있다면 테스트해줘야합니다.
•
declare module과 같은 any를 주의해야합니다.
7장 코드를 작성하고 실행하기
53. 타입스크립트 기능보다는 ECMAScript 기능을 사용하기
•
열거형, 매개변수 속성, 트리플 슬래시 임포트, 데코레이터는 타입 정보를 제거한다고 JS가 되지 않기때문에 사용을 피하는 것이 좋습니다.
54. 객체를 순회하는 노하우
const obj = {
one: 'uno',
two: 'dos',
three: 'tres'
};
for (const k in obj) {
const v = obj[k]; // k는 string으로 추론됩니다.
}
// 해결법
let k: keyof typeof obj;
for (const k in obj) {
const v = obj[k];
}
JavaScript
복사
interface ABC {
a: string;
b: string;
c: number;
}
function foo(abc: ABC){
for (const k in abc) {
const v = abc[k]; // k: string
}
}
// foo 함수는 ABC 타입에 할당 가능한 어떤 값이든 매개변수로 허용하기 때문에 d가 가능합니다.
// 따라서 할당 가능한 객체의 key 값은 string으로 인식하게됩니다.
const x = {a: 'a', b: 'b', c: 2, d: new Date());
foo(x); // 정상
JavaScript
복사
// 타입 에러 상관없이 사용하려면 Object.entires를 사용하면 됩니다.
...
for(const [k, v] of Object.entries(abc))
JavaScript
복사
•
키값을 정확히 파악하고 있다면 keyof T와 for-in을 사용하고, 일반적으론 Object.entries를 사용합니다.
55. DOM 계층 구조 이해하기
•
EventTarget은 DOM 타입 중 가장 추상화된 타입입니다. 이벤트 리스터 추가, 제거, 보내기 밖에 할 수 없습니다.
•
Node는 텍스트와 주석을 포함하고 있습니다.
•
Element는 HTMLElement와 SVGElement를 포함합니다.
•
HTMLxxxxElement는 각자 고유한 속성을 가지고 있습니다.
•
DOM querySelector등의 경우엔 사용자가 더 잘 알고 있는 경우가 많아 단언이나 if 분기를 처리해주면 됩니다.
56. 정보를 감추는 목적으로 private를 사용하지 않기
•
public, protected, private는 TS에서만 강제되고 런타임에선 소용이 없으므로 데이터를 감추고 싶다면 클로저를 사용해야합니다.
57. 소스맵을 사용하여 타입스크립트 디버깅하기
•
sourcemap 컴파일 옵션을 통해 디버깅을하고, 공개되지 않도록 확인해야합니다.
8장 타입스크립트로 마이그레이션하기
58. 모던 자바스크립트로 작성하기
•
ECMAScript 모듈을 사용하세요
•
프로토타입 대신 클래스를 사용하세요.
•
var 대신 let/const 사용하기
•
for(;;) 대신 for-of 또는 배열 메서드 사용하기
•
함수 표현식보단 화살표 함수 사용하기단축 객체 표현과 구조 분해 할당 사용하기
•
함수 매개변수 기본값 사용하기
•
저수준 프로미스나 콜백 대신 async/await 사용하기
•
연관 배열에 객체 대신 Map과 Set 사용하기
•
타입스크립트에 use strict 넣지 않기
59. 타입스크립트 도입 전에 @ts-check와 JSDoc으로 시험해 보기
•
//@ts-check를 상단에 추가시 js도 타입체크를 할 수 있습니다.
•
전역변수로 인해 문제 발생시 선언 파일을 추가해주면 됩니다.
// @ts-check
/// <reference path="./types.d.ts" />
JavaScript
복사
•
DOM 관련 에러는 JSDoc을 사용해 타입 단언을 대체할 수 있습니다.
// @ts-check
const ageEl = /** @type {HTMLInputElement} */)document.getElementById('age'));
JavaScript
복사
60. allowJs로 타입스크립트와 자바스크립트 같이 사용하기
•
기존의 빌드 방식에 TS 컴파일러는 추가하기 위해선는 allowJs 옵션이 필요합니다.
61. 의존성관계에 따라 모듈 단위로 전환하기
•
최우선적으로 서드파티 모듈과 외부 API 호출에 대해 @types 를 추가해줘야합니다.
•
의존성 최하단부터 위로 올라가며 작업을 진행합니다.
•
JSDoc 주석을 활용해줍시다.
62. 마이그레이션의 완성을 위해 noImplicityAny
•
작업 중 임시로 any로 대체해둔 경우가 많으므로 noImplicityAny 옵션을 통해 any들을 제거해줍니다.