이펙티브 타입스크립트(2)
2-1. 편집기를 사용하여 타입 시스템 탐색하기
•
타입스크립트 컴파일러 (tsc)
•
단독으로 실행할 수 있는 타입스크립트 서버 (tsserver)
◦
코드 자동 완성
◦
명세(사양, specification) 검사
◦
검색
◦
리팩토링
2-2. 타입이 값들의 집합이라고 생각하기
•
타입스크립트에서 가장 작은 집합은 아무 값도 포함하지 않는 공집합이며, 이를 never 라고 부른다
◦
never 타입은 어떠한 값도 할당할 수 없다
•
never 다음으로 작은 집합은 한 가지 값만 포함하는 타입이고, 이를 unit 타입이라고 불리는 literal 타입이다
◦
literal 을 여러개로 묶으려면 union 타입을 사용한다
예시 코드
•
extends 키워드는 제네릭 타입에서 한정자로도 사용되며, ~의 부분 집합 이라는 의미를 가지고 있다
정리
•
타입을 값의 집합으로 생각하면 이해하기 편하다 (타입의 범위)
◦
집합은 유한(boolean 또는 literal)하거나 무한(string 또는 number)하다.
•
타입스크립트 타입은 엄격한 상속 관계가 아니라 겹쳐져 있는 집합으로 표현된다
◦
두 타입은 서로 서브타입이 아니면서도 겹쳐질 수 있다
•
한 객체의 추가적인 속성이 타입 선언에 언급되지 않더라도 그 타입에 속할 수 있다
•
타입 연산은 집합의 범위에 적용된다
◦
객체 타입에서는 A & B 인 값이 A 와 B 의 속성을 모두 가짐을 의미한다.
•
A 는 B 를 상속, A 는 B 에 할당 가능 , A 는 B 의 서브타입 은 A 는 B 의 부분 집합 과 같은 의미이다\
2-3. 타입 공간과 값 공간의 심벌 구분하기
•
타입스크립트의 심벌(symbol)은 타입 공간이나 값 공간 중의 한 곳에 존재한다
•
이름이 같더라도 속하는 공간에 따라 다른 것을 나타낼 수 있기 때문에 혼란을 야기할 수 있다
◦
아래의 예시는 Cylinder 라는 이름은 같지만, 서로 아무런 관련이 없다
◦
일반적으로 type 이나 interface 의 심벌은 타입인 반면, const 나 let 선언에 쓰이는 것은 값이다
예시 코드
•
class 와 enum 은 상황에 따라 타입과 값 두 가지 모두 가능한 예약어이다
◦
class 는 타입으로 쓰일 때는 형태 (property, method) 가 사용되는 반면, 값으로 사용될 때는 생성자가 사용된다
예시 코드
•
typeof와 같이 연산자 중에서도 타입에서 쓰일 때와 값에서 쓰일 때 다른 기능을 하는 것들이 있다
예시 코드
•
자바스크립트의 런타임 타입 시스템은 타입스크립트 타입과는 다르다
◦
자바스크립트 런타임 타입 시스템은 타입스크립트 정적 타입 시스템보다 훨씬 간단하다
◦
타입스크립트 타입의 종류는 무수히 많은 반면, 자바스크립트는 6개(string, numebr, boolean, undefined, object, function) 의 런타임 타입만 존재한다
•
자바스크립트 vs 타입스크립트 차이
◦
this
▪
다형성(polymorphic) this 라고 불리는 this 의 타입스크립트 타입이다
•
서브클래스의 메서드 체인을 구현할 때 유용
◦
& 와 |
▪
자바스크립트: AND 와 OR 비트연산자
▪
타입스크립트: Intersection 와 Union
◦
const
▪
as const 는 리터럴 또는 리터럴 표현식의 추론된 타입을 변경
◦
extends
▪
서브 클래스 또는 서브 타입 또는 제네릭 한정자를 정의
◦
in
▪
반복문 (for (key in object))) 또는 매핑된(mapped) 타입
정리
•
모든 값은 타입을 가지지만, 타입은 값을 가지지 않는다
◦
type 과 interface 는 타입 공간에만 존재한다
•
class 나 enum 은 타입과 값 두가지 모두 사용할 수 있다
•
typeof, this 그리고 많은 연산자들과 키워드들은 타입 공간과 값 공간에서 다른 목적으로 사용될 수 있다
2-4. 타입 단언보다는 타입 선언을 사용하기
•
타입스크립트 변수에 값을 할당하고 타입을 부여하는 방법은 2가지가 있다
◦
타입 단언 (type assertion)
◦
타입 선언 (type annotation)
예시 코드
•
타입 선언은 할당되는 값이 해당 인터페이스를 만족하는지 검사하지만, 타입 단언은 강제로 타입을 지정해서 타입 에러를 무시한다
◦
타입 단언이 꼭 필요한 경우가 아니라면, 안정성 체크도 되는 타입 선언을 사용하는것이 좋다
예시 코드
•
not null assertion (!) 은 null 이 아님을 단언하는 경우 사용한다
◦
타입 체커는 nullable 한지 알지 못하지만, 그 값이 null 이 아니라고 확신하는 경우에만 사용해야 한다.
예시 코드
•
타입 단언문으로 임의의 타입 간에 변환을 할 순 없다
◦
타입이 부분집합 인 경우에 타입 단언문을 사용해 변환할 수 있다
◦
이를 강제로 해결하려면 unknown 을 사용해야 한다
▪
모든 타입은 unknown 의 서브타입이기 때문에 unknown 이 포함된 단언문은 항상 동작한다
예시 코드
정리
•
타입 단언 보다는 타입 선언을 사용해야 한다
•
화살표 함수의 반환 타입을 명시하는 방법을 알아야 한다
•
타입스크립트보다 타입 정보를 더 잘 알고 있는 상황에서는 타입 단언문과 null 아님 단언문을 사용하면 된다
2-5. 객체 래퍼 타입 피하기
•
자바스크립트에는 객체 이외에도 기본형 값들에 대한 일곱가지 타입이 있다
◦
타입: string, number, boolean, null, undefined, symbol, bigint
◦
string, number, boolean, null 은 자바스크립트 초창기부터 존재했다
◦
symbol 기본형은 ES2015 에 추가되었다
◦
bigint 는 최종 확정 단계에 있다
•
기본형들은 불변(immutable) 이며 메소드를 가지지 않는다
•
자바스크립트는 기본형과 객체 타입을 서로 자유롭게 변환한다
◦
string 기본형에 charAt 같은 메소드를 사용할 때, 자바스크립트는 기본형을 String 객체로 래핑하고, 메소드를 호출하고 마지막에 래핑된 객체를 버린다.
◦
String 객체를 직접 생성할 수 있으며, string 기본형처럼 동작한다.
▪
그러나 string 기본형과 String 객체 래퍼가 항상 동일하게 동작하지 않는다
•
String 객체는 오직 자기자신하고만 동일하다.
예시 코드
◦
null 과 undefined 는 객체 래퍼가 없다
•
래퍼 타입들 덕분에 기본형 값에 메소드를 사용할 수 있고, 정적 메소드도 사용할 수 있다
◦
하지만, 래퍼 객체를 직접 생성할 필요는 없다
•
타입스크립트가 제공하는 타입 선언은 전부 기본형 타입으로 되어 있다
◦
타입스크립트는 기본형 타입을 객체 래퍼로 할당하는 선언을 허용하지만, 이렇게 사용할 경우 오해하기 쉽기 땜누에 기본형 타입을 사용하는것이 낫다
요약
•
기본형 값에 메소드를 제공하기 위해 객체 래퍼 타입이 어떻게 사용되는지 이해해야 한다
◦
직접 사용하거나 인스턴스를 생성하는것은 피해야 한다
•
타입스크립트 객체 래퍼 타입은 지양하고, 기본형 타입을 사용해야 한다
2-6. 잉여 속성 체크의 한계 인지하기
•
타입이 명시된 변수에 객체 리터럴을 할당할 때 타입스크립트는 해당 타입의 속성이 있는지, 그 외의 속성은 없는지 확인한다
예시 코드
•
잉여 속성 체크를 이용하면 기본적으로 타입 시스템의 구조적 본질을 헤치지 않으면서도 객체 리터럴에 알 수 없는 속성을 허용하지 않는다
◦
엄격한 객체 리터럴 체크 라고도 불린다
•
잉여 속성 체크는 타입 단언문을 사용할 때에도 적용되지 않는다
◦
타입 단언문보다 타입 선언문을 사용해야 하는 이유 중 하나이다
•
잉여 속성 체크를 원하지 않는다면, 인덱스 시그니처를 사용해서 타입스크립트가 추가적인 속성을 예상할 수 있도록 할 수 있다
예시 코드
•
선택적 속성만 가지는 약한(weak) 타입에도 비슷한 체크가 동작한다
예시 코드
•
잉여 속성 체크는 구조적 타이핑 시스템에서 허용되는 속성 이름의 오타 같은 실수를 잡는데 효과적인 방법이다
요약
•
객체 리터럴을 변수에 할당하거나, 함수에 매개변수로 전달할 때 잉여 속성 체크가 수행된다
•
잉여 속성 체크는 오류를 찾는 효과적인 방법이지만, 타입스크립트 타입 체커가 수행하는 일반적인 구조적 할당 가능성 체크와 역할이 다르다
•
잉여 속성 체크에는 한계가 있다
◦
임시 변수를 도입하면 잉여 속성 체크를 건너뛸 수 있다
2-7. 함수 표현식에 타입 적용하기
•
자바스크립트와 타입스크립트에서 함수 문장(statement) 와 함수 표현식 (expression) 을 다르게 인식한다.
◦
타입스크립트에서는 함수 표현식을 사용하는것이 좋다
◦
함수의 매개변수부터 반환값까지 전체를 함수 타입으로 선언하여 함수 표현식에서 재사용할 수 있기 때문이다
예시 코드
•
다른 함수의 시그니처와 동일한 타입을 가지는 새 함수를 작성하거나, 동일한 타입 시그니처를 가지는 여러개이 함수를 작성할 때는 매개변수의 타입과 반환 타입을 반복해서 작성하지 말고 함수 전체의 타입 선언을 적용해야 한다
정리
•
매개변수나 반환 값에 타입을 명시하기보다는 함수 표현식 전체에 타입 구문을 적용하는것이 좋다
•
만약 같은 타입 시그니처를 반복적으로 작성한 코드가 있다면 함수 타입을 분리하는게 좋다
•
다른 함수의, 시그니처를 참조하려면 typeof fn 을 사용하면 된다