Blog

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

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

2-8. 타입과 인터페이스의 차이점 알기

인터페이스는 타입을 확장할 수 있으며, 타입은 인터페이스를 확장할 수 있다
인터페이스는 유니온 타입 같은 복잡한 타입을 확장하지는 못한다
복잡한 타입을 확장하고 싶으면 타입과 Intersection 을 사용해야 한다
타입은 유니온 타입에 추가적인 속성을 붙일 수 있다
예시 코드
튜플과 배열 같은 타입도 타입을 이용해 더 간결하게 표현할 수 있다
예시 코드
인터페이스는 보강(augment) 가 가능하다
예시 코드처럼 속성을 확장하는 것을 선언 병합 (declaration merging) 라고 한다.
예시 코드
타입스크립트는 여러 버전의 자바스크립트 표준 라이브러리에서 여러 타입을 모아 병합해서 제공해준다
타입과 인터페이스 중 어느 것을 사용해야 할까?
복잡한 타입이라면 type 을 사용 한다
타입과 인터페이스 모두 표현 할 수 있는 객체 타입이면 일관성과 보강의 관점에서 고려해서 사용한다

요약

한 타입을 type 과 interface 두 가지 문법을 사용해서 작성하는 방법을 알아야 한다
프로젝트에서 어떤 문법을 사용할지 결정할 때 한 가지 일관된 스타일을 확립하고, 보강 기법이 필요한지 고려해야 한다

2-9. 타입 연산과 제네릭 사용으로 반복 줄이기

타입 중복은 코드 중복만큼 많은 문제를 발생시킨다
타입에서 중복이 더 흔한 이유 중 하나는 공유된 패턴을 제거하는 메커니즘이 기존 코드에서 하던 것과 비교해 덜 익숙하기 때문이다
함수가 같은 타입 시그니처를 공유하는 경우 NamedType 으로 분리해낼 수 있다
예시 코드
상태를 표현하는 State 타입과 표현 부분만 처리하는 타입이 있는 경우 인덱싱하여 속성의 타입 중복을 제거할 수 있다
예시 코드
타입 연산자와 유용한 타입
keyof
typeof
Partial
ReturnType

요약

DRY (don't repeat yourself) 원칙을 타입에도 최대한 적용해야 한다
타입에 이름을 붙여서 반복을 피해야 한다
extends 를 사용해서 인터페이스 필드의 반복을 피해야 한다
타입들 간의 매핑을 위해 타입스크립트가 제공한 도구들을 사용하면 좋다
제네릭 타입은 타입을 위한 함수와 같다
제네릭 타입을 제한하려면 extends 를 사용하면 된다
표준 라이브러리에 정의된 제네릭 타입에 익숙해져야 한다

2-10. 동적 데이터에 인덱스 시그니처 사용하기

타입에 인덱스 시그니처 를 명시하여 유연하게 동적 타입을 매핑할 수 있다
예시 코드
인덱스 시그니처의 단점
1.
잘못된 키를 포함해도 모든 키를 허용한다
2.
특정 키가 필요하지 않는다
3.
키마다 다른 타입을 가질 수 없다
4.
타입스크립트 언어 서비스가 도움이 되지 않는다
인덱스 시그니처는 동적 데이터를 표현할 때 주로 사용한다
e.g.) CSV 파일처럼 헤더 행(row) 에 열 (column) 이 있고, 데이터 행을 열 이름과 값으로 매핑하는 객체로 나타내고 싶은 경우
인덱스 시그니처를 사용할 때 너무 광범위하게 타입을 매핑할 수 있으므로 선택적 필드나 유니온 타입으로 모델링하면 좋다
예시 코드

요약

런타임 때까지 객체의 속성을 알 수 없는 경우메나 인덱스 시그니처를 사용해야 한다
안전한 접근을 위해 인덱스 시그니처의 값 타입에 undefined 를 추가하는 것을 고려해야 한다
가능하다면 인터페이스, Record, 매핑된 타입 같은 인덱스 시그니처보다 정확한 타입을 사용하는것이 좋다

2-11. number 인덱스 시그니처보다는 Array, 튜플, ArrayLike 를 사용하기

자바스크립트에서 객체는 Key-Value 쌍의 모음이다.
키는 보통 문자열이며, ES2015 이후로는 Symbol 일 수 있다
객체에서 number 는 key 로 사용할 수 없다
자바스크립트 런타임은 숫자를 넣은 경우 문자열로 변환한다
예시 코드
어떤 길이를 가지고 있는 배열과 비슷한 형태의 튜플을 사용하고 싶다면 ArrayLike 타입을 사용한다
예시 코드

정리

배열은 객체이므로 키는 숫자가 아니라 문자열이다
인덱스 시그니처로 사용된 number 타입은 버그를 잡기 위한 순수 타입스크립트 코드이다
인덱스 시그니처에 number 를 사용하기 보다 Array 나 튜플, 또는 ArrayLike 타입을 사용하는 것이 좋다

2-12. 변경 관련된 오류 방지를 위해 readonly 사용하기

매개변수를 readonly 로 선언하면 발생하는 일
타입스크립트에서는 매개변수가 함수 내에서 변경이 일어나는지 체크한다
호출하는 쪽에서 함수가 매개변수를 변경하지 않는다는 보장을 받게 된다
호출하는 쪽에서 함수에 readonly 배열을 매개변수로 넣을 수 있다
자바스크립트(타입스크립트)에서는 명시적으로 언급하지 않는 한, 함수가 매개변수를 변경하지 않는다고 가정한다
하지만, 암묵적인 방법은 타입 체크에 문제를 발생할 수 있다
명시적인 방법을 사용하는 것이 컴파일러와 사람에게 모두 좋다
타입스크립트의 타입을 좀 더 잘 표현하기 위해서 ts-essentials 를 도입해보는것도 좋을듯하다

정리

만약 함수가 매개변수를 수정하지 않는다면 readonly 로 선언하는것이 좋다
readonly 를 사용하면 변경하면서 발생하는 오류를 방징할 수 있고, 변경이 발생하는 코드도 쉽게 찾을 수 있다
const 와 readonly 의 차이를 이해해야 한다
readonly 는 얕게 동작 한다. (shallow)

2-13. 매핑된 타입을 사용하여 값을 동기화하기

보수적(conservative) 접근법 (실패에 닫힌 접근법)
실패에 닫힌(fails close) 방법은 오류 발생 시에 적극적으로 대처하는 방향을 말한다
실패에 열린 방법은 오류 발생 시에 소극적으로 대처하는 방향이다
보안과 관련된 곳이라면 실패에 닫힌 방법을 사용해야 하고, 기능에 무리가 없고 사용성이 중요한 곳이라면 실패에 열린 방법을 사용해야 한다
매핑된 타입과 객체를 사용해서 타입 체커가 동작하도록 해야한다
예시 코드

정리

매핑된 타입을 사용해서 관련된 값과 타입을 동기화해야 한다
인터페이스에 새로운 속성을 추가할 때, 선택을 강제하도록 매핑된 타입을 고려해야 한다