Blog

이펙티브 타입스크립트(3)

이펙티브 타입스크립트(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 와 같은 유틸리티 라이브러리를 사용하는것이 좋다