item 58. 모던 자바스크립트로 작성하기
•
ECMAScript 모듈 사용하기
◦
ES2015부터는 import와 export를 사용하는 ECMAScript 모듈이 표준이 되었고 만약 마이그레이션 대상이 자바스크립트 코드가 단일 파일이거나 비표준 모듈 시스템이라면 전환하는 것이 좋다.
•
프로토타입 대신 클래스 사용하기
◦
과거 자바스크립트는 프로토타입 기반의 객체 모델을 사용했으나 많은 개발자들이 견고하게 설계된 클래스 기반 모델을 선호해 ES2015에 class 키워드를 사용하는 클래스 기반 모델이 도입되었다.
◦
기존 코드가 단순한 객체를 다룰 때 프로토타입을 사용하고 있다면 클래스로 전환하는 것이 좋다.
•
var 대신 let/const 사용하기
◦
자바스크립트 var 키워드의 스코프 규칙에 문제가 있다는 것은 널리 알려진 사실이다.
◦
반면 let과 const는 제래도 된 블록 스코프 규칙을 가지며 개발자들이 일반적으로 기대하는 방식으로 동작한다.
•
for(;;)대신 for-of 또는 배열 메소드 사용하기
◦
for-of 루프는 코드가 짧고 인덱스 변수를 사용하지도 않기 때문에 실수를 줄일 수 있다. 인덱스 변수가 필요한 경우엔 배열의 forEach 메소드를 사용하면 된다.
◦
for-in 문법도 존재하지만 몇 가지 문제점이 존재하기 때문에 사용하지 않는 것이 좋다.
•
함수 표현식보다 화살표 함수 사용하기
◦
this 키워드는 일반적인 변수들과 다른 스코프 규칙을 가지기 때문에 다음과 같은 상황에서 상위 스코프의 this를 유지해야 한다면 화살표 함수를 사용하는 것이 적절하다.
class Foo {
method() {
console.log(this);
[1, 2].forEach(i => {
console.log(this);
});
}
}
const f = new Foo();
f.method();
// Always prints Foo, Foo, Foo
TypeScript
복사
•
단축 객체 표현과 구조 분해 할당 사용하기
◦
선언하려는 변수와 사용되는 객체의 속성 이름이 같다면 다음 코드처럼 간결하게 작성할 수 있다.
const x = 1, y = 2, z = 3;
const pt = { x, y, z };
TypeScript
복사
◦
후자의 코드가 더 간결하고 중복된 이름을 생략하기 때문에 가독성이 좋고 실수가 적다.
•
함수 매개변수 기본값 사용하기
◦
자바스크립트 함수의 모든 매개변수는 선택적이며 매개변수를 지정하지 않으면 undefined로 간주된다.
◦
매개변수에 기본값을 지정하면 코드가 간결해질 뿐만 아니라 base가 선택적 매개변수임을 명확히 나타내는 효과도 줄 수 있다.
•
저수준 프로미스나 콜백 대신 async/await 사용하기
◦
async와 await을 사용하면 코드가 간결해져서 버그나 실수를 방지할 수 있고 비동기 코드에 타입 정보가 전달되어 타입 추론에 용이하다.
function getJSON(url: string) {
return fetch(url).then(response => response.json());
}
function getJSONCallback(url: string, cb: (result: unknown) => void) {
// ...
}
TypeScript
복사
◦
위 코드 대신 다음과 같이 작성하라.
async function getJSON(url: string) {
const response = await fetch(url);
return response.json();
}
TypeScript
복사
•
연관 배열에 객체 대신 Map과 Set 사용하기
•
타입스크립트에 use strict 넣지 않기
◦
타입스크립트가 수행하는 안전성 검사가 엄격 모드보다 훨씬 더 엄격한 체크를 하기때문에 타입스크립트 코드에선 무의미하다.
•
요약
◦
타입스크립트 개발 환경은 모던 자바스크립트도 실행할 수 있으므로 모던 자바스크립트의 최신 기능들을 적극적으로 사용하라. 코드 품질을 향상시킬 수 있고 타입 추론도 더 나아진다.
◦
타입스크립트 개발 환경에서는 컴파일러와 언어 서비스를 통해 클래스, 구조 분해, async/await 같은 기능을 쉽게 배울 수 있다.
◦
use strict는 타입스크립트 컴파일러 수준에서 사용되므로 코드에서 제거해야 한다.
◦
TC39의 깃허브 저장소와 타입스크립트의 릴리스 노트를 통해 최신 기능을 확인하면 좋다.
item 59. 타입스크립트 도입 전에 @ts-check와 JSDoc으로 시험해 보기
•
타입스크립트로 전환하기에 앞서 @ts-check를 이용해 전환 시 어떤 문제가 발생하는지 미리 시험해볼 수 있다.
◦
@ts-check 지시자를 사용하면 타입 체커가 파일을 분석하고 발견된 오류를 보고하도록 지시한다. 그러나 이는 매우 느슨한 수준으로 타입 체크를 수행하는 점을 주의해야 한다.
•
다음은 @ts-check가 찾아내는 몇 가지 의미있는 오류들이다.
◦
선언되지 않은 전역 변수
◦
알 수 없는 라이브러리
◦
부정확한 JSDoc
•
요약
◦
파일 상단에 //@ts-cehck를 추가하면 자바스크립트에서도 타입 체크를 수행할 수 있다.
◦
JSDoc 주석을 잘 활용하면 자바스크립트 상태에서도 타입 단언과 타입 추론을 할 수 있다.
item 60. allowJs로 타입스크립트와 자바스크립트 같이 사용하기
•
allowJs 컴파일러 옵션을 사용하면 타입스크립트 파일과 자바스크립트 파일을 서로 임포트할 수 있게 해준다.
•
이 과정에서 빌드와 테스트가 동작하게 해야한다. 제대로 된 점진적 마이그레이션을 달성하기 위해 필요하다.
•
요약
◦
점진적 마이그레이션을 위해 자바스크립트와 타입스크립트를 동시에 적용할 수 있게 allowJs 컴파일러 옵션을 사용하자.
◦
대규모 마이그레이션 작업을 진행하면서 테스트와 빌드 체인에 타입스크립트를 적용해야 한다.
item 61. 의존성 관계에 따라 모듈 단위로 전환하기
•
점진적 마이그레이션을 수행할 때, 모듈 단위로 진행하는 것이 이상적이다. 그러나 한 모듈을 골라서 타입 정보를 추가하면 해당 모듈이 의존하는 모듈에서 비롯되는 타입 오류가 발생하게 된다.
•
의존성과 관련된 오류없이 작업을 성공적으로 끝마치려면 다른 모듈에 의존하지 않는 최하단 모듈부터 작업을 시작해서 의존성의 최상단에 있는 모듈을 마지막으로 완성해야 한다.
•
먼저 서드파티 라이브러리의 타입 정보를 해결해야 한다.
◦
이들은 내부 모듈에 의존하지 않기 때문이다. 일반적으로 @types 모듈을 설치하면 되는데 보편적으로 @types/라이브러리명이 타입 정보를 담고 있기 때문이다.
•
외부 API를 호출하는 경우도 있기 때문에 외부 API의 타입 정보도 추가해야 한다.
•
이후 마이그레이션을 진행하는 데, 이때 타입 정보 추가만하고 리팩토링을 수행해서는 안 된다.
◦
코드 개선이 아닌 마이그레이션이 목표기 때문이다.
•
이 과정에서 item 59이 다루지 않은 나머지 발생 가능한 오류들에 대해서 알아보자.
◦
선언되지 않은 클래스 멤버
▪
자바스크립트는 클래스 멤버 변수를 선언할 필요가 없다. 따라서 존재하지 않을 수 있다.
▪
이는 IDE의 빠른 수정으로 간단히 해결할 수 있다. 언어 서비스가 타입 추론을 통해 멤버를 추가해준다. 이후 타입을 훑어보면서 적절히 바꿔주자.
◦
타입이 바뀌는 값
•
이후 테스트 코드를 타입스크립트로 전환하면 된다.
•
요약
◦
마이그레이션의 첫 단계는 서드파티 모듈과 외부 API 호출에 대한 @types 의존성을 추가하는 것이다.
◦
의존성 관계도의 아래에서부터 위로 올라가며 마이그레이션을 수행하면 된다. 첫 번째 모듈은 보통 유틸리티 모듈이다.
▪
이 과정에서 의존성 관계도를 시각화하여 진행 과정을 추적하는 것이 좋다.
◦
리팩토링을 해선 안 된다. 마이그레이션 작업은 타입스크립트 전환에 집중해야 하며, 나중의 리팩토링을 위해 목록을 작성해두자.
◦
타입스크립트로 전환하며 발견하게 되는 일반적인 오류들을 놓치지 않아야 한다.
▪
때에 따라 타입 정보를 유지하기 위해 JSDoc 주석을 활용해야 할 수도 있다.
item 62. 마이그레이션의 완성을 위해 noImplicitAny 사용하기
•
프로젝트 전체를 .ts로 마이그레이션한 후, 마지막 단계는 noImplicitAny를 설정하는 것이다.
•
해당 옵션이 설정되지 않은 상태에서는 타입 선언에서 비롯되는 실제 오류가 숨어 있기 때문에 완전하게 마이그레이션되었다고 할 수 없다.
•
처음에는 해당 옵션을 로컬에서만 설정하는 것이 좋다. 로컬에서만 오류로 인식되기 때문에 수정된 부분만 커밋할 수 있기 때문이다.
•
타입 체크의 강도는 팀 내의 모든 사람이 타입스크립트에 익숙해진다음 천천히 올리는 것이 좋다.
•
요약
◦
noImplicitAny 설정을 활성화하여 마이그레이션의 마지막 단계를 진행해야 한다.
▪
noImplicitAny 설정이 없다면 타입 선언과 관련된 실제 오류가 드러나지 않는다.
◦
noImplicitAny를 전면 적용하기 전에 로컬에서부터 타입 오류를 점진적으로 수정해야 한다.