본문 바로가기
책/이펙티브 타입스크립트

[이펙티브 타입스크립트] 1장 타입스크립트 알아보기

by 오오오오니 2025. 3. 18.
 
아이콘 추가
커버 추가
레이아웃 사용자 지정

1장 타입스크립트 알아보기

 
2024년 12월 17일 오후 2:48
댓글
 
 
 
 
 
 

🔹 아이템 1: 타입스크립트와 자바스크립트의 관계 이해하기

타입스크립트는 자바스크립트의 상위 집합
 
 
 
타입스크립트는 자바스크립트의 상위집합이기 때문에 .js 파일에 있는 코드는 이미 타입스크립트라고 할 수 있다.
 
 
모든 자바스크립트 프로그램이 타입스크립트라는 명제는 참이지만, 그 반대는 성립하지 않는다.
 
타입스크립트가 타입을 명시하는 추가적인 문법을 가지기 때문
 
 
타입 시스템의 목표 중 하나는 런타임에 오류를 발생시킬 코드를 미리 찾아내는 것
 
 
타입스크립트는 타입 구문 없이도 오류를 잡을 수 있지만, 타입 구문을 추가한 다면 훨씬 더 많은 오류를 찾아낼 수 있다.
 
코드의 ‘의도’가 무엇인지 타입 구문을 통해 타입스크립트에게 알려줄 수 있기 때문
 
 
 
 
AI에게 질문하기
 
 
 
 
 
 
 
 
 
자바스크립트의 런타임 동작을 모델링하는 것은 타입스크립트 타입 시스템의 기본 원칙
 
복사
캡션
 
const names = ['Alice', 'Bob']; console.log(names[2].toUpperCase()); 프로그램을 실행하면 다음과 같은 오류가 발생합니다. TypeError: Cannot read property 'toUpperCase' of undefined
 
 
타입 시스템은 정적 타입의 정확성을 보장해 줄 목적으로 만들어지지도 않았다.
 
 
타입 체커를 통과하면서도 런타임 오류를 발생시키는 코드는 충분히 존재할 수 있다.
 

🔹 아이템 2: 타입스크립트 설정 이해하기

 
noImplicitAny : 변수들이 미리 타입을 가져야 하는지 여부
 
 
strictNullChecks : null과 undefined을 모든 타입에서 할당할 수 있는지 여부
 
설정하지 않으면 undefined는 객체가 아닙니다. 라는 런타임 오류를 주의
 
⇒ 기본값이 false로 설정되어 있어서 추가로 설정해야함
 
strict : true - 한 번에 설정하는 법
 
그 외
복사
캡션
 
{ "compilerOptions": { "module": "commonjs", //모듈시스템 설정 "declaration": true, //타입 선언 파일 생성 ex) index.ts -> index.d.ts "removeComments": true, //컴파일 시 주석을 제거 "emitDecoratorMetadata": true, //런타임에서 클래스와 같은 데코레이터의 메타데이터를 추가. reflect-metadata 라이브러리와 함께 사용된다. "experimentalDecorators": true, //데코레이터 기능을 사용하려면 설정해야한다. "allowSyntheticDefaultImports": true, //export default가 없는 모듈에서도 import default 문법을 사용 "target": "es2017", //자바스크립트 버전 "sourceMap": true, // 디버깅을 위해 .map 생성 - 컴파일된 코드랑 TypeScript코드를 연결 - 브라우저 개발자 도구에서 원본 코드 확인 가능 "outDir": "./dist", // 출력 디렉토리 "baseUrl": "./", //모듈 경로 기준 "incremental": true, //이전 컴파일을 캐시하여 컴파일 속도를 개선 "skipLibCheck": true, //라이브러리 타입 체크 생략(ex) node_modules) - 컴파일 시간 단축에 도움됨 "strictNullChecks": false, //null 체크 할당 가능 여부 "noImplicitAny": false, //타입 선언 없는 변수를 any로 볼지 여부 "strictBindCallApply": false, //bind, call, apply 타입 체크 비활성화 "forceConsistentCasingInFileNames": false, // 파일명 대소문자 일관성 체크 "noFallthroughCasesInSwitch": false // switch 문 Fallthrough 방지 비활성화 } }
 

🔹 아이템 3: 코드 생성과 타입이 관계없음을 이해하기

 
타입스크립트 컴파일러는 두 가지 역할을 수행
 
 
최신 타입스크립트/자바스크립트를 브라우저에서 동작할 수 있도록 구버전 의 자바스크립트로 트랜스파일
 
 
코드의 타입 오류를 체크
 
 
⇒ 두 가지는 독립적
 
타입 검사는 개발 시점에만 일어나고,트 랜스파일링된 JavaScript 코드는 타입 정보 없이 실행
 
타입 오류를 고쳐도 JavaScript 코드 실행에 직접적인 영향 x , 타입 오류를 무시해도 JavaScript 코드가 실행 가능
 

런타임에 타입 정보를 유지하는 방법

 
속성 체크 : 타입 가드
 
if ('height' in shape)
 
 
태그 기법 사용
 
Shape타입은 ‘태그된 유니온(tagged union)’의 한 예
 
복사
캡션
 
interface Square { kind: 'square'; width: number; } interface Rectangle { kind: 'rectangle'; height: number; width: number; }
 
 
타입을 클래스 만들기
 
런타임에 접근 가능한 값을 사용
 
 
클래스라서 instanceof 사용 가능
 
복사
캡션
 
if(shape instanceof Rectangle) //값으로 참조됨 - item 8에서 다룬다.
 
 
⇒ 타입스크립트 타입은 런타임에 사용 할수 없음. 런타임에 타입을 지정하려면 별도의 방법 필요.

런타임 타입은 선언된 타입과 다를 수 있다

 
자바스크립트라면 불린값 이외의 값 넣을 수 있다.
 
 
타입스크립트도 가능
 
api 응답으로 받아온 값을 넣었는데 잘못된 값이였을 때
 
복사
캡션
 
function setLightSwitch(value: boolean) { switch (value) { case true: turnLightOn(); break; case false: turnLightOff(); break; default: console.log(`실행되지 않을까 봐 걱정됩니다.`); } }
 
 
 
타입으로 함수 오버로드 할 수 없다.
 
 
타입스크립트 타입은 런타임 성능에 영향을 주지 않는다
 
빌드타임 오버헤드 있음
 

🔹 아이템 4: 구조적 타이핑에 익숙해지기

 
덕 타이핑 기반
 
 
함수 매개변수 값을 전부 가지고 있다면 사용
 
 
 
 
Vector2D와 NamedVector의 관계를 전혀 선언하지 않았음
 
NamedVector의 구조가 Vector2D와 호환 → 구조적 타이핑
 
 
calculateLength는 2D 벡터를 기반으로 연산하는데, 버그로 인해 normalize가 3D 벡터로 연산되었습니다.
 
z가 정규화에서 무시
 
 
이런 경우를 처리하는 설정이 존재 → 아이템 37
 
 
v는 어떤 속성이든 가질 수 있기 때문에, axis의 타입은 string이 될 수 있다.
 
즉, number라고 확정할 수 없다.
 
 
할당문에서도 구조적 타이핑
 
만약 생성자가 단순 할당이 아니라 연산 로직이 존재하면 문제가 발생된다.
 
복사
캡션
 
//1 interface Vector2D { x: number; y: number; } function calculateLength(v: Vector2D): number { return Math.sqrt(v.x * v.x + v.y * v.y); } interface NamedVector { name: string; x: number; y: number; } const v: NamedVector = { x: 3, y: 4, name: 'Zee', }; calculateLength(v); // 정상, 결과는 5 //===================== interface Vector3D { x: number; y: number; z: number; } function normalize(v: Vector3D): Vector3D { const length = calculateLength(v); //2d벡터로 계산하는 함수 return { x: v.x / length, y: v.y / length, z: v.z / length, }; } //2. 1.41 출력 > normalize({x: 3, y: 4, z: 5}) { x: 0.6, y: 0.8, z: 1 } //3 function calculateLengthL1(v: Vector3D) { let length = 0; for (const axis of Object.keys(v)) { const coord = v[axis]; // ~~~~~~~ 'string'은 'Vector3D'의 인덱스로 사용할 수 없기에 length += Math.abs(coord); // 엘리먼트는 암시적으로 'any' 타입입니다. } return length; } const vec3D = { x: 3, y: 4, z: 1, address: '123 Broadway', }; //4 const c = new C('instance of C'); const d: C = { foo: 'object literal' }; // 정상!
 
 
⇒ 타입은 열려있다.
 
 
구조적 타이핑은 단위 테스트 할 때 유리하다.
 
테스트 코드에서 실제 환경의 데이터 베이스 정보 불필요.
 
 
DB를 추상화 함으로써 로직과 테스트를 특정한 구현으로부터 분리
 
 
 

🔹 아이템 5: any 타입 지양하기

 
any 타입에는 타입 안정성이 없다
 
 
any는 함수 시그니처를 무시한다.
 
 
any 타입에는 언어 서비스가 적용되지 않는다
 
 
any 타입은 코드 리팩터링 때 버그를 감춘다.
 
 
any는 타입 설계를 감춘다.
 
 
any는 타입시스템의 신뢰도를 떨어뜨린다.
 
 
⇒ 최대한 사용을 피하자
 
 
 
조혜온
2024. 12. 17.
?
 
조혜온
2024. 12. 17.
Type Narrowing Type Guards 타입 체커 TODO: 블로그 주제 TODO: DENO 알아보기 타입체커 원리 코드 파싱 → AST 생성 바인딩: 심볼과 스코프를 연결 타입 검사: 타입 추론 및 타입 가드 적용 흐름 분석(Control Flow Analysis)을 통해 타입 좁히기 수행 타입 호환성 검사 트랜스파일: 타입 정보를 제거하고 JavaScript로 변환
 
조혜온
2024. 12. 17.
증분 빌드?
 
 
 
 
 
 
 
 
 
저작자표시