본문 바로가기
Book Review/Effective Typescript

day2_effectfive-typescript스터디

by 예 강 2023. 6. 16.

2022년 11월 26일글입니다.

2장 타입스크립트의 타입시스템

 

item6. 편집기를 사용하여 타입시스템 탐색하기

요약 : 타입스크립트 서버가 제공하는 코드 자동완성, 명세검사, 검색, 리팩터링 등의 언어서비스를 누려라

  1. 타입스크립트 서버덕분에 편집기에 마우스를 올려 어떤 타입인지 알 수 있다.
  2. ctrl+클릭 같은 Go To Definition 기능 을 이용해서 타입이 어떻게 정의 되어있는지 알 수 있다.
  3. 타입스크립트의 자동완성기능을 누릴 수 있다.

 


item7. 타입이 값들의 집합이라고 생각하기

 

요약 1 : 타입을 할당 가능한 값의 집합 이라고 생각해라
요약 2 : 한 객체의 추가적인 속성이 타입 선업에 언급되지 않더라도, 그 타입에 속할 수 있다.(구조적 타이핑)
요약 3 : 타입 연산은 집합의 범위에 적용된다.

 

요약 1 . 타입을 할당 가능한 값의 집합이라고 생각해라

타입을 할당 가능한 값의 집합이라고 생각해야 타입을 이해하는데 더 쉽다고 저자는 말한다.

1. never 타입 === 공집합

const x : never = 12 // never타입엔 12 할당 불가

따라서 가장 작은 집합, 즉 아무값도 포함하지 않는 공집합은 타입에서는 never 타입이다.

2. 리터럴타입(literal) 유닛타입 (unit)

공집합 다음으로 작은 타입인 한가지 값만 포함하는 집합

type A : 'A';
type B : 'B';
type Twelve : 12;

3. 유니온타입(union)

type AB = 'A' | 'B' | 'C'

유니온 타입은 값 집합들의 합집합을 의미한다.

집합의 관점에서 볼 때, 타입체커의 주요 역할을 이해 할 수 있는데
타입 체커는 하나의 집합이 다른집합의 부분집합인지 검사한다.

AB12는 AB의 부분집합이 아니다.

요약 2 : 한 객체의 추가적인 속성이 타입 선업에 언급되지 않더라도, 그 타입에 속할 수 있다.(구조적 타이핑)
요약 3 : 타입 연산은 집합의 범위에 적용된다.

4. 인터섹션 타입(intersection)



타입연산자는 인터페이스의 속성 이 아닌, 값의 집합(타입의 범위) 에 적용되기 때문에 & 연산은 Person과 Lifespan을 둘다 가지는 값이 됩니다.

구조적 타이핑때문에 세가지에 추가로 더 많은 속성을 가져도 PersonSpan 속성에 속한다.

그러나 유니온 타입에선 좀 다르다.

keyof는 항상 접근가능한 유형의 키를 반환해야 하는데, Person과 Lifespan 사이엔 공통되는 어떠한 키도 없어서 공집합(never) 이 된다.

 

요약하자면

keyof(A&B) = (keyof A ) | ( keyof B)
keyof(A|B) = (keyof A ) & ( keyof B)

로 동작한다.


Item8. symbol이 Typespace와 ValueSpace 중 어디에 있는지 파악하기

요약 1 : 타입으로 쓰이는지, 값으로 쓰이는지 잘 파악하는 방법을 터득해야 한다.
요약 2: 모든 값은 타입을 가지지만, 타입은 값을 가지지 않는다.
요약 3: class나 enum 같은 키워드는 타입과 값 두가지로 사용될 수 있다.
요약 4: 타입공간이냐 값 공간이냐에 따라 typeof와 this의 쓰임이 달라진다.

요약 1 : 타입으로 쓰이는지, 값으로 쓰이는지 잘 파악하는 방법을 터득해야 한다.

위쪽은 타입으로 Cylinder가 선언되어 있고 아래쪽은 값으로 Cylinder가 선언되어 있다.
그러면 타입스크립트는 어떤 Cylinder인지 어떻게 구분할까 ?
그 때 타입공간, 값 공간 이라는 개념이 나온다.

instanceof 는 런타임 연산자라서 값 Cylinder에 대해 연산을 하기 때문에 오류가 발생한다.

때문에 이런 오류를 줄이려면 문맥을 잘 살펴서 값 공간인지 타입공간 (저자는 공간이라고 표현)인지 잘 살펴야한다.

 

요약 2 : 모든 값은 타입을 가지지만, 타입은 값을 가지지 않는다.

런타임 시에 모두 날라가기 때문이다.

요약 3: class나 enum 같은 키워드는 타입과 값 두가지로 사용될 수 있다.

class는 런타임 단계에서도 살아남기 때문에 instanceof Cylinder 에서 오류를 내지 않는다.

 

요약 4: 타입공간이냐 값 공간이냐에 따라 typeof와 this의 쓰임이 달라진다.

타입 T1에서 typeof는 p 의 타입을 반환한다.
타입 T2에서 typeof는 email 의 타입을 반환한다.
값 v1 에서 typeof는 p의 값을 반환한다.
값 v1 에서 typeof는 emai의 값을 반환한다.

  • 값으로 쓰이는 this는 자바스크립트의 this 키워드고, 타입으로 쓰이는 this는 일명 다형성의 this이다. (아이템49에서 더 알아보자)
  • 값에서 &와 | 는 OR, AND 비트연산이지만 타입에서는 인터섹션과 유니온 연산이다.

 

타입스크립트에서 자주 봤던 오류인데, props 디스트럭팅을 할때 저런식으로 Person을 값으로 인식해버리는 문제이다.

나는 type space로 읽힐 줄 알았으나 값의 공간 문맥으로 해석되어 Person 과 string을 생성하려고 해서 뜨는 오류였던 것이다.

이걸 해결하기 위해선

디스트럭팅 시 이런식으로 타입공간과 값 공간을 분리해서 타입을 선언해 주어야 한다.


Item9. 타입 단언(as) 보다는 타입 선언을 사용하기

요약 1: 타입단언 (as Type) 보다는 타입 선언(:Type)사용하기
요약 2: 화살표 함수의 반환타입을 명시하는 방법을 터득하자.
요약 3: 타입스크립트보다 타입정보를 더 잘 알고있을땐 타입 단언문(as Type) 과 null 아님 단언문을 사용하자(!)

요약 1: 타입단언 (as Type) 보다는 타입 선언(:Type)사용하기

 

타입 단언보다 타입 선언을 사용하는게 나은데,

  • (1) 타입스크립트가 추론한 타입을 무시하며
  • (2) 타입체커에게 타입을 지정했으니 오류를 무시하라고 하며
  • (3) 잉여속성체크도 무시한다.

즉 오류가 날 가능성이 더 크니 타입 선언문을 주로 사용하고 as 는 꼭 필요한 경우에만 쓰자!

요약 2: 화살표 함수의 반환타입을 명시하는 방법을 터득하자.

 

우리가 type이 Person[] 인 people을 얻고싶다고 할 때, 위처럼 하면 될것 같지만 사실 안된다.


이런식으로 화살표 함수에서 리턴타입을 명시해주는 방법을 사용하자.

 

요약 3: 타입스크립트보다 타입정보를 더 잘 알고있을땐 타입 단언문(as Type) 과 null 아님 단언문을 사용하자(!)

as 나 ! 가 쓰여야 하는 상황이 종종있는데 그 중 하나는

  • HTML DOM Element를 받아오는 상황 처럼 as T를 쓰는게 타당하다, 타입스크립트는 DOM에 접근할 수 없기 때문이다.
  • 마찬가지로 ! 도 우리가 판단할 때 값이 NULL 이 아니면 사용하자.
  • 단언문은 컴파일 과정에 제거되므로, 타입체커는 알지 못한다. 그러니 개발자가 확실하게 파악하고 사용하자.

Item10. 객체 래퍼 타입 피하기

요약 1: 기본형 값에 메서드를 제공하기위해 객체 래퍼타입이 어떻게 쓰이는지 이해하고, 직접 사용하거나 인스턴스를 생성하는건 피해라

 

자바스크립트엔 객체 이외에도 기본형 값들에 대한 일곱가지 타입이 있다.
(string, number, boolean, null, undefind, symbol, bigint)

기본형들은 immutable 하고 메서드를 가지지 않는 점에서 객체와 구분된다.
그러나 우린

"apple".charAt(3) // "l"

과 같은 방법을 굉장히 많이 썼다. 기본형이 string인데 어떻게 쓴걸까?
그건 바로 기본형으로 메서드를 쓰기위해 String객체로 변환해서 사용되었기 때문이다.


자바스크립트에선 기본형과 객체타입을 서로 자유롭게 변환하는데 그래서 charAt같은 메서드를 쓸 때

  • 기본형을 String 객체로 래핑(wrap)한다.
  • 메서드를 호출한다.
  • 마지막에 래핑한 객체를 버린다.

기본형은 객체 래퍼 타입에 할당할 수 있지만 객체 래퍼 타입은 기본형에 할당 할 수 없다.
래퍼 객체는 첫 글자를 대문자로 표기하기 때문에 기본형과 구분된다.