October 02, 2022
이펙티브 타입스크립트를 읽고 공부한 것을 기록합니다.
{
"compilerOptions:{
"noImplicity":true
}
}
타입스크립트는 타입 정보를 가질 때 가장효과적이기에, 되도록이면 noImplicitAny
를 설정해줘야 한다.
모든 변수에 타입을 명시하는 것에 익숙해지면, noImplicitAny가 없는 채로 작성된 타입스크립트는 완전히 다른 언어처럼 느껴질 것이다.
새 프로젝트를 시작한다면 처음부터 noImplicitAny
를 설정하여 코드를 작성할 때마다 타입을 명시하도록 해야한다.
그러면, 타입스크립트가 문제를 발견하기 수월해지고, 코드의 가독성이 좋아지며, 개발자의 생산성이 향상된다.
noImplicitAny
설정 해제는 자바스크립트로 되어있는 기존 프로젝트를 타입스크립트로 전환하는 상황에만 필요하다.
noImplicitAny
를 설정하는 것이 좋다.undefined
는 객체가 아닙니다같은 런타임 오류를 방지하기 위해 strictNullCheck를 설정하는 것이 좋다.타입스크립트 컴파일러는 두 가지 역할을 수행한다.
타입 오류가 있는 코드도 컴파일이 가능하다
컴파일은 타입체크와 독립적으로 동작하기에 타입오류가 있는 코드도 컴파일이 가능하다.
런타임에는 타입체크가 불가능하다
interface Square {
width: number
}
interface Rectangle extends Square {
height: number
}
type Shape = Square | Rectangle
function calculateArea(shape: Shape) {
if (shape instanceof Rectangle) {
return shape.width * shape.height
} else {
return shape.width * shape.width
}
}
instanceof 체크는 런타임에 일어나지만, Rectangle은 타입이기에 런타임 시점에 아무런 역할을 할 수 없다.
자바스크립트는 본질적으로 덕 타이핑
기반이다. 만약 어떤 함수의 매개변수 값이 모두 제대로 주어진다면, 그 값이 어떻게 만들어졌는지 신경쓰지 않고 사용한다.
타입스크립트는 매개변수 값이 요구사항을 만족한다면 타입이 무엇인지 신경쓰지 않는 동작을 그대로 모델링한다.
구조적 타이핑을 제대로 이해한다면 오류인 경우와 오류가 아닌 경우의 차이를 알 수 있고, 더욱 견고한 코드를 작성할 수 있다.
interface Vector 2D {
x:number;
y:number;
}
interface Vector 3D{
x:number;
y:number;
z:number;
}
function calculateLength(v:Vector2D){
return Math.sqrt(v.x*v.x+v.y*v.y)
}
function normalize(v:Vector3D) {
const length = calculateLength(v);
return{
x:v.x/length;
y:v.y/length;
z:v.z/length;
}
}
// 이 함수는 1보다 조금 더 긴(1.41)길이를 가진 결과를 출력할 것이다.
> normalize({x:3,y:4,z:5})
타입스크립트가 오류를 잡지 못한 이유를 생각해보면,
calculateLength
는 2D 벡터를 기반으로 연산하는데, 버그로 인해 normalize가 3D벡터로 연산되었다.
z가 정규화에서 무시된 것이다.
그런데 타입체커가 이 문제를 잡아내지 못했다. calculateLength
가 2D벡터를 받도록 선언되어있음에도 3D벡터를 받는데 문제가 없었던 이유는 무엇일까?
Vector3D와 호환되는 {x,y,z}객체로 calculateLength
를 호출하면, 구조적 타이핑 관점에서 x와 y가 있어서 Vector2D로 호환된다.
따라서 오류가 발생하지 않았고, 타입체커가 문제로 인식하지 않았다.
일부 특별한 경우를 제외하고는 any를 사용하면 타입스크립트의 수많은 장점을 누릴 수 없게 된다. 부득이하게 any를 사용하더라도 그 위험성을 알고 있어야 한다
any는 함수 시그니처를 무시해버린다.
함수를 작성할 때는 시그니처를 명시해야 한다. 호출하는 쪽은 약속된 타입의 입력을 제공하고, 함수는 약속된 타입의 출력을 반환한다.
그러나 any타입을 사용하면 이런 약속을 어길 수 있다.
any타입은 타입 설계를 감춘다
애플리케이션 상태 같은 객체를 정의하려면 꽤 복잡하다. 상태 객체 안에 있는 수많은 속성의 타입을 일일이 작성해야 하는데, any타입을 사용하면 간단히 끝내버릴 수 있다.
물론 이때도 any를 사용하면 안된다.any를 사용하면 타입 설계가 불분명해진다. 설계가 명확히 보이도록 타입을 일일이 작성하는게 좋다.
any는 타입시스템의 신뢰도를 떨어뜨린다
타입체커가 실수를 잡아주고 코드의 신뢰도를 높일 수 있다.any타입을 쓰지 않으면 런타임에 발견될 오류를 미리 잡을 수 있고 신뢰도를 높일 수 있다.
타입스크립트를 쓰고 있지만, 여전히 모르는 부분이 많다고 느껴져서 이펙티브타입스크립트 공부를 시작했다.
여전히 타입에러는 많이나고 어쩔 수 없이 any를 많이 쓰고 있는 나를 볼 때, 더 공부가 필요하다는 생각이 많이 든다.
이번 파트를 공부하며 새 프로젝트에 noImplicitAny
를 설정하여 코드를 작성할 때마다 타입을 명시하도록 해줬다!
이펙티브 타입스크립트 책을 보면 이해가 잘 안되는 부분이나 지금 나에게 필요하지 않아보이는 내용도 있었다. 그 부분은 스킵하고 필요한 부분이라고 생각하는 부분만
집중적으로 읽고 공부를 해볼 계획이다-!