[Effective Typescript]타입스크립트 알아보기

이예슬·2022년 10월 23일
0

Effective TypeScript

목록 보기
1/15

타입스크립트와 자바스크립트의 관계 이해하기

💡 타입스크립트는 자바스크립트의 superset(상위집합)이다.

타입스크립트는 자바스크립트의 상위 집합입니다.

즉 모든 자바스크립트 프로그램은 타입스크립트이지만 그 반대는 성립하지 않습니다.

이는 타입스크립트가 타입을 명시하는 추가적인 문법을 가지기 때문입니다.

모든 자바스크립트는 타입스크립트이지만 일부 자바스크립트만이 타입 체크를 통과합니다.

타입스크립트 타입 시스템은 자바스크립트의 런타임 동작을 모델링하는 타입 시스템을 가지고 있기 때문에 런타임 오류를 발생시키는 코드를 찾아내려고 합니다. 그러나 모든 오류를 찾아낼 수는 없고 타입 체커를 통과하면서도 런타임 오류를 발생시키는 코드도 존재할 수 있습니다.

타입스크립트 설정 이해하기

function add(a, b){
	return a + b;
}
add(10, null)

위의 코드가 오류업이 타입 체커를 통과할 수 있을까요? 유효한 코드인지 아닌지 바로 대답을 했다면 타입스크립트의 설정에 대해 아직 이해하지 못하고 있는 것입니다. 앞선 질문은 타입스크립트의 설정이 어떻게 되어 있는지 모른다면 대답할 수 없는 질문입니다.

타입 스크립트는 설정에 따라 완전히 다른 언어처럼 느껴질수도 있습니다. 그리고 이러한 설정을 제대로 사용하려면 noImplicitAnystrictNullChecks를 이해해야 합니다.

위 코드는 noImplicitAny 가 해제되어 있을 때에 유효합니다. noImplicitAny 는 변수들이 미리 정의된 타입을 가져야 하는지에 대한 여부를 제어합니다.

strictNullChecksnullundefined가 모든 타입에서 허용되는지 확인하는 설정입니다.

const x: number = null // 정상 null은 유효한 값이다. 
const x: number = null // error 'null' 형식은 'number' 형식에 할당할 수 없다. 
const x: number | null = null // 만약 null을 허용하려고 하면 의도를 명시적으로 드러냄으로 오류를 고칠 수 있다. 

이 외에도 타입스크립트 컴파일러는 거의 100개에 이르는 설정을 가지고 있으며 이는 커맨드라인을 사용하여 설정할수도 있지만 가급적이면 tsconfig.json 파일에서 설정하는 것이 좋습니다. 언어에 의미적으로 영향을 미치는 설정들을 모두 체크하고 싶다면 strict 설정을 하면 됩니다.

아래 사이트에서 타입스크립트의 컴파일 옵션들을 확인할 수 있습니다.

https://www.typescriptlang.org/tsconfig

(참고로 tsconfig.json에서 프로젝트의 절대경로 또한 설정할 수 있습니다.)

코드 생성과 타입이 관계없음을 이해하기

타입스크립트 컴파일러는 크게 두 가지 역할을 수행합니다.

  • 최신 타입스크립트/자바스크립트를 브라우저에서 동작할 수 있도록 구버전의 자바스크립트로 트랜스파일한다.
  • 코드의 타입 오류를 체크한다.

이 두 가지는 서로 완벽히 독립적입니다. 이 두 가지가 서로 완벽하게 독립적이므로 타입 오류가 있는 코드도 컴파일이 가능합니다. 만약 오류가 있을 때 컴파일하지 않기를 원한다면 tsconfig.jsonnoEmitOnError를 설정하거나 빌드 도구에 동일하게 적용하면 됩니다.

런타임에는 타입 체크가 불가능합니다. 실제로 자바스크립트로 컴파일 되는 과정에서 모든 인터페이스, 타입, 타입 구문은 제거됩니다.

이러한 문제를 해결하기 위해 런타임에서도 타입 정보를 유지하기 위한 방법으로는 속성 체크를 추가 하거나 태그 기법을 사용할 수 있습니다. 그 중에서도 태그 기법은 런타임에 접근 가능한 타입 정보를 명시적으로 저장하는 방법입니다.

interface Square {
	kind: 'square';
	width: number;
}

interface Rectangle {
	kind: 'rectangle';
	height: number;
	width: number;
}

type Shape = Square | Rectangle; 

function calculateArea(shape: Shape) {
	if(shape.kind === 'rectangle') {
		shape;
		return shape.width * shape.height;
	}else{
		shape;
		return shape.width * shape.width
	}
}

위의 코드에서 Shape는 태그된 유니온의 예시입니다. 이 기법은 런타임에 타입 정보를 손쉽게 유지할 수 있어 타입스크립트에서 흔하게 볼 수 있습니다.

앞서 언급한 두 가지 방법 이외에도 타입과 값을 둘 다 사용하여 타입을 클래스로 만드는 방법 또한 사용할 수 있습니다. 타입스크립트에서 인터페이스는 타입으로만 사용가능하지만 클래스로 선언할 경우 타입과 값으로 모두 사용할 수 있으므로 오류가 발생하지 않게 됩니다.

타입 스크립트의 타입 연산은 런타임에 영향을 주지 않습니다. 즉 타입은 런타임 성능에 영향을 주지 않습니다.

any 타입 지양하기

타입스크립트의 타입 시스템은 코드에 타입을 조금씩 추가할 수 있기 때문에 점진적이고 언제든지 타입 체커를 해제할 수 있기 때문에 선택적입니다.

그리고 이러한 기능들의 핵심은 any 타입입니다.

타입스크립트를 사용해 코드를 작성하다 보면 타입 선언을 추가하는 데에 시간을 쏟고 싶지 않거나 어떤 타입이 선언되어야 하는지 명확하게 설계하지 않을 때 any 타입이나 타입 단언문(as any)을 사용하고 싶어질 때가 있습니다.

하지만 일부 특수한 경우를 제외하고는 any 타입을 사용할 경우 타입스크립트의 장점을 누릴 수 없습니다. 또한 부득이하게 any 타입을 사용하게 되더라도 그 위험성에 대해 알고 있어야 합니다.

  • any 타입에는 타입 안정성이 없다.
  • any는 함수 시그니처를 무시한다. 함수에서 호출하는 쪽은 약속된 타입의 입력을 제공하고 함수는 약속된 타입의 출력을 반환해야 합니다. 그러나 any를 사용하면 이러한 약속을 어길 수 있습니다.
  • any 타입에는 언어 서비스가 적용되지 않는다.
  • any 타입은 코드 리팩토링 때 버그를 감춘다.
  • any는 타입 설계를 감춘다.
  • any는 타입 시스템의 신뢰도를 떨어뜨린다.

<이펙티브 타입스크립트> Dan Vanderkam, 프로그래밍 인사이트 (2021)

profile
꾸준히 열심히!

0개의 댓글