이펙티브 타입스크립트(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) 방법은 오류 발생 시에 적극적으로 대처하는 방향을 말한다
•
실패에 열린 방법은 오류 발생 시에 소극적으로 대처하는 방향이다
•
보안과 관련된 곳이라면 실패에 닫힌 방법을 사용해야 하고, 기능에 무리가 없고 사용성이 중요한 곳이라면 실패에 열린 방법을 사용해야 한다
•
매핑된 타입과 객체를 사용해서 타입 체커가 동작하도록 해야한다
예시 코드
정리
•
매핑된 타입을 사용해서 관련된 값과 타입을 동기화해야 한다
•
인터페이스에 새로운 속성을 추가할 때, 선택을 강제하도록 매핑된 타입을 고려해야 한다