이펙티브 타입스크립트(3)
3-1. 추론 가능한 타입을 사용해 장황한 코드 방지하기
•
정보가 부족해 타입스크립트가 스스로 타입을 판단하기 어려운 상황인 경우 명시적 타입 구문이 필요하다.
예시 코드
•
이상적인 타입스크립트 코드는 함수/메서드 시그니처에 타입 구문을 포함하지만, 함수 내에서 생성된 지역 변수에는 타입 구문을 넣지 않는다
◦
타입 구문을 생략하여 방해되는 것들을 최소화하고 코드를 읽는 사람이 구현 로직에 집중할 수 있게 하는것이 좋다
•
함수 구문에 기본값이 있는 매개변수는 타입을 생략하는게 좋다
예시 코드
•
객체 리터럴을 정의할 때는 타입을 명시하는게 좋다
◦
객체 리터럴을 정의할 때 타입을 정의해주지 않으면 잉여 속성 체크가 동작하지 않는다
예시 코드
•
함수에서 리턴 타입을 명시하는것이 좋다
1.
오류의 위치를 제대로 표시해준다
2.
함수에 대해 더욱 명확하게 알 수 있다
3.
명명된 타입을 사용할 수 있다
•
반환 타입을 명시하면 더욱 직관적인 표현이 가능하다
예시 코드
정리
•
타입스크립트가 타입을 추론할 수 있다면 타입 구문을 작성하지 않는게 좋다
•
이상적인 경우 함수/메서드의 시그니처에는 타입 구문이 있지만, 함수 내의 지역 변수에는 타입 구문이 없다
•
추론될 수 있는 경우라도 객체 리터럴과 함수 반환에는 타입 명시를 고려해야 한다
3-2. 다른 타입에는 다른 변수 사용하기
•
변수를 무분별하게 재사용하면 타입 체커와 코드를 읽는 사람에게 혼란을 줄 수 있다
•
다른 타입에는 별도의 변수를 사용하는게 바람직하다
◦
서로 관련이 없는 두개의 값을 분리한다
◦
변수명을 더 구체적으로 지을 수 있다
◦
타입 추론을 향상시키며, 타입 구문이 불필요해진다
◦
타입이 좀 더 간결해진다
◦
let 대신 const 로 변수를 선언하게 된다
▪
const 로 변수를 선언하면 코드가 간결해지고, 타입 체커가 타입을 추론하기에도 좋다
•
타입이 바뀌는 변수는 되도록 피해야하며, 목적이 다른 곳에는 별도의 변수명을 사용해야 한다
요약
•
변수의 값은 바뀔 수 있지만 타입은 일반적으로 바뀌지 않는다
•
혼란을 막기 위해 타입이 다른 값을 다룰 때에는 변수를 재사용하지 않도록 한다
3-3. 타입 넓히기
•
런타임에 모든 변수는 유일한 값을 가진다. 하지만, 타입스크립트가 작성된 코드를 체크하는 정적 분석 시점에, 변수는 가능한 값들의 집합인 타입을 가진다
•
상수를 사용해서 변수를 초기화할 때 타입을 명시하지 않으면 타입 체커는 타입을 결정해야 한다
◦
지정된 단일 값을 가지고 할당 가능한 값들의 집합을 유추해야 한다 → 이를 타입스크립트에서는 넓히기(widening) 라고 한다
예시 코드
•
타입 추론의 강도를 직접 제어하려면 타입스크립트 기본 동작을 재정의해야한다
1.
명시적 타입 구문을 제공한다
2.
타입 체커에 추가적인 문맥을 제공한다
3.
const 단언문을 사용한다
요약
•
타입스크립트가 넓히기를 통해 상수의 타입을 추론하는 법을 이해해야 한다
•
동작에 영향을 줄 수 잇는 방법인 const, 타입 구문, 문맥, const 단언문에 익숙해져야 한다
3-4. 타입 좁히기
•
타입스크립트가 넓은 타입으로부터 좁은 타입으로 진행하는 과정을 말한다
◦
일반적인 예시는 null 체크이다
예시 코드
•
타입을 좁히는 방법은 여러가지 있다
1.
분기문
a.
예외를 던지거나, 함수를 반환하여 나머지 부분에서의 타입을 좁힐 수 있다
2.
instanceof 를 사용
3.
Array.isArray 와 같은 일부 내장 함수 사용
4.
명시적 태그 를 붙이는 방법
•
태그된 유니온 (Tagged Union) 또는 구별된 유니온 (Discriminated Union) 이라 불림
예시 코드
5.
사용자 정의 타입 가드 사용
예시 코드
요약
•
분기문 외에도 여러 종류의 제어 흐름을 살펴보면 타입스크립트가 타입을 좁히는 과정을 이해해야 한다
•
태그된/구별된 유니온과 사용자 정의 타입 가드를 사용하여 타입 좁히기 과정을 원활하게 만들 수 있다
3-5. 한꺼번에 객체 생성하기
•
객체를 생성할 때는 속성을 하나씩 추가하기보다는 여러 속성을 포함해서 한꺼번에 생성해야 타입 추론에 유리하다
•
객체 전개 연산자를 사용하면 타입 걱정 없이 필드 단위로 객체를 생성할 수 있다
•
객체 전개 연산자를 사용할 때 선택적 필드 방식으로 표현하려면 헬퍼 함수를 사용하면 된다
예시 코드
요약
•
속성을 제각각 추가하지 말고 한꺼번에 객체로 만들어야 한다
◦
안전한 타입으로 속성을 추가하려면 객체 전개를 사용하면 된다
•
객체에 조건부로 속성을 추가하는 방법을 익혀야 한다
3-6. 일관성 있는 별칭 사용하기
•
별칭은 타입스크립트가 타입을 좁히는것을 방해한다
◦
변수에 별칭을 사용할 때는 일관되게 사용해야 한다
•
비구조화 문법을 이용해서 일관된 이름을 사용하는것이 좋다
예시 코드
•
함수 호출이 객체의 속성의 타입 정제를 무효화할 수 있다는 점을 주의해야 한다
◦
속성보다 지역 변수를 사용하면 타입 정제를 믿을 수 있다
3-7. 비동기 코드에는 콜백 대신 async 함수 사용하기
•
타입스크립트 컴파일러는 async/await 가 동작하도록 정교한 변환을 수행한다.
◦
타입스크립트는 런타임에 관계없이 async/await 를 사용할 수 있다
•
callback 보다 promise 혹은 async/await 를 사용해야 하는 이유
1.
코드를 작성하기 쉽다
2.
타입을 추론하기 쉽다
•
promise 보다 async/await 를 사용해야 하는 이유
1.
일반적으로 더 간결하고 직관적인 코드가 된다
2.
async 함수는 항상 promise 를 반환하도록 강제된다
•
async 함수에서 Promise 를 반환하면 또 다른 Promise 로 Wrapping 되지 않는다
◦
반환 타입은 Promise<Promise<T>>> 가 아니고 Promise<T> 가 된다
3-8. 타입 추론에 문맥이 어떻게 사용되는지 이해하기
•
타입 추론에서 문맥이 어떻게 쓰이는지 주의해서 살펴봐야 한다
•
변수를 뽑아서 별도로 선언했을 때 오류가 발생한다면 타입 선언을 추가해야 한다
•
변수가 정말 상수라면 상수 단언을 사용해야 한다
◦
상수 단언을 사용하면 정의한곳이 아니라 사용한 곳에서 오류가 발생하므로 주의해야 한다
3-9. 함수형 기법과 라이브러리로 타입 흐름 유지하기
•
자바스크립트에서 서드파티 라이브러리를 사용해서 코드를 짧게 줄이는데 시간이 많이 필요하다면 사용하지 않는게 더 좋을 수 있다
◦
하지만, 타입스크립트로 작성하면 서드파티 라이브러리를 사용하는 것이 무조건 유리하다 (e.g. lodash, underscore, ramda 등 )
◦
타입스크립트에서 타입 정보가 그대로 유지되면서 타입 흐름이 계속 전달되기 때문이다
•
타입 흐름을 개선하고, 가독성을 높이고, 명시적인 타입 구문의 필요성을 줄이기 위해 직접 구현하기보다는 내장된 함수형 기법과 lodash 와 같은 유틸리티 라이브러리를 사용하는것이 좋다