diff --git a/typescript/onebite/yujin/ch0.md b/typescript/onebite/yujin/ch0.md new file mode 100644 index 0000000..e08f1f6 --- /dev/null +++ b/typescript/onebite/yujin/ch0.md @@ -0,0 +1,68 @@ +요청하신 내용을 바탕으로 가독성을 높인 **Markdown** 형식의 정리본입니다. 강의 자료나 수강생 안내 가이드로 바로 활용하시기 좋습니다. + +--- + +# 0챕터. 성공적인 실습을 위한 환경 설정 가이드 + +본격적인 강의 수강에 앞서, 실습에 필요한 핵심 도구들을 설치하고 확인하는 과정을 진행합니다. + +--- + +## 1. 강의 핵심 도구 소개 + +원활한 타입스크립트 실습을 위해 아래 두 가지 도구를 반드시 준비해 주세요. + +* **Node.js (18버전 권장):** 자바스크립트/타입스크립트 실행 환경 +* **Visual Studio Code (VS Code):** 코드 편집기(에디터) + +--- + +## 2. Node.js 설치 및 확인 + +타입스크립트 코드를 직접 실행해보기 위해 필수적으로 설치해야 합니다. + +### 권장 버전: LTS (Long Term Support) + +LTS는 오랜 기간 안정적으로 지원되는 버전을 의미합니다. 안정성이 검증된 **16, 18, 20 버전** 중 하나를 설치하세요. + +### 설치 방법 + +1. [Node.js 공식 홈페이지](https://nodejs.org/)에 접속합니다. +2. 좌측의 **LTS**라고 적힌 다운로드 버튼을 클릭합니다. +3. 다운로드된 설치 파일을 실행하여 설치를 완료합니다. + +### 설치 확인 + +터미널(또는 명령 프롬프트)을 열어 아래 명령어를 입력하여 확인합니다. + +| 명령어 | 용도 | 기대 결과 | +| --- | --- | --- | +| `node -v` | Node.js 버전 확인 | v16.x.x, v18.x.x, v20.x.x 등 출력 | +| `npm -v` | npm 버전 확인 | 설치된 npm 버전 번호 출력 | + +> **💡 Tip:** 만약 버전이 출력되지 않거나 오류가 발생한다면, 터미널을 완전히 종료 후 다시 실행해 보세요. 여전히 안 된다면 기존 프로그램을 제거하고 재설치하는 것을 권장합니다. + +--- + +## 3. Visual Studio Code (VS Code) 설치 + +전 세계 프로그래머들이 가장 선호하는 에디터인 VS Code를 준비합니다. + +* **설치 방법:** [VS Code 공식 홈페이지](https://code.visualstudio.com/)에서 본인의 운영체제(Windows/macOS)에 맞는 설치 파일을 다운로드하여 설치합니다. +* **참고:** VS Code의 버전은 실습 결과에 큰 영향을 주지 않으므로 최신 버전을 사용하시면 됩니다. + +--- + +## 4. 추가 설정 및 팁 (Optional) + +### 🇰🇷 한국어 팩 설치 + +VS Code의 기본 언어는 영어입니다. 한국어 메뉴가 편하신 분들은 아래 과정을 참고하세요. + +1. VS Code 좌측의 **Extensions(확장)** 아이콘 클릭 +2. `Korean Language Pack` 검색 후 설치 +3. VS Code 재실행 + +### 📦 npm이란? + +**Node Package Manager**의 약자로, Node.js 설치 시 함께 제공되는 도구입니다. 외부 라이브러리(패키지)를 설치, 삭제, 업데이트할 때 사용하며 앞으로의 실습에서 자주 활용하게 됩니다. \ No newline at end of file diff --git a/typescript/onebite/yujin/ch1.md b/typescript/onebite/yujin/ch1.md new file mode 100644 index 0000000..6d5aded --- /dev/null +++ b/typescript/onebite/yujin/ch1.md @@ -0,0 +1,368 @@ +# 1-0. 타입스크립트를 소개합니다 + +본격적인 문법 학습에 앞서, 우리가 배우려는 이 언어가 **어디서 왔는지, 왜 쓰는지, 그리고 왜 지금 배워야만 하는지** 그 배경을 깊이 있게 살펴보기 + +![alt text](image.png) + +--- + +## 1. 타입스크립트의 탄생: 거장의 손에서 태어나다 + +타입스크립트는 단순한 유행이 아니라 명확한 설계 철학을 바탕으로 탄생했습니다. + +* **출시:** 2012년 마이크로소프트(Microsoft) 발표 +* **설계자:** **앤더스 하일스버그(Anders Hejlsberg)** +* C#, Delphi, Turbo Pascal을 만든 전설적인 엔지니어입니다. +* 그의 영향으로 타입스크립트는 C#과 유사한 객체지향적 특징과 견고한 구조를 갖추게 되었습니다. + + +* **생태계:** 완전한 **오픈소스(Open Source)**로 관리되어 전 세계 개발자들이 실시간으로 발전시키고 있습니다. + +--- + +## 2. 왜 '대세'인가? (압도적 인기와 시장성) + +타입스크립트는 이제 선택이 아닌 필수가 되고 있습니다. + +* **사용자 통계:** 2022년 `StateOfJS` 설문에 따르면, 자바스크립트 개발자 100명 중 **89명**이 이미 사용 중입니다. +* **취업 시장:** 프론트엔드/백엔드를 막론하고 채용 공고의 자격 요건에 빠지지 않는 **단골 스택**입니다. +* **학습 선호도:** 국내 프로그래머스 설문(2023) 결과, **가장 배우고 싶은 언어 2위**(자바스크립트 개발자들 사이에서는 압도적 1위)로 선정될 만큼 높은 관심을 받고 있습니다. + +--- + +## 3. 타입스크립트의 정체: 자바스크립트의 확장판(Superset) + +타입스크립트는 자바스크립트와 완전히 다른 언어가 아닙니다. + +* **확장판(Superset) 개념:** 자바스크립트가 가진 모든 기본 문법과 기능을 그대로 유지하면서, 그 위에 **'타입(Type)' 시스템**을 얹은 언어입니다. +* **쉬운 전환:** 이미 알고 있는 자바스크립트 코드에 타입 정의만 추가하면 바로 타입스크립트가 됩니다. +* **JS:** `let sum = (a, b) => a + b;` +* **TS:** `let sum = (a: number, b: number): number => a + b;` + +* **익숙함:** 자바스크립트 숙련자라면 새로운 언어를 배우는 부담 없이, 타입을 다루는 추가 기능만 익혀서 프로젝트에 바로 적용할 수 있습니다. + +--- + +## 4. 자바스크립트의 한계와 타입스크립트의 등장 배경 + +자바스크립트만으로도 충분한데 왜 굳이 타입스크립트를 써야 할까요? 그 이유는 자바스크립트의 **'지나친 유연함'** 때문입니다. + +### ① 자바스크립트의 탄생 목적 (과거) + +* 원래 웹 브라우저에서 버튼 클릭, 팝업 띄우기 등 아주 간단한 상호작용을 처리하기 위해 만들어졌습니다. +* 빠르고 간결하게 작성하는 것이 목표였기에, 엄격한 문법보다는 유연함을 택했습니다. + +### ② Node.js와 자바스크립트의 전성기 (현재) + +* Node.js의 등장으로 자바스크립트가 서버, 모바일 앱(React Native), 데스크탑 앱(Electron) 등 **대규모 복잡한 프로그램**을 만드는 데 쓰이기 시작했습니다. +* 간단한 작업에서는 장점이었던 **'유연함'**이, 대규모 프로젝트에서는 어디서 터질지 모르는 **'불안정성'**이라는 단점으로 변했습니다. + +### ③ 해결사로서의 타입스크립트 + +* 대규모 어플리케이션에서도 안정적으로 동작할 수 있도록, 기존 자바스크립트의 매력은 살리되 **'타입'이라는 안전장치**를 추가한 것이 바로 타입스크립트입니다. + +--- + +## 5. 요약: 우리가 타입스크립트를 배우는 이유 + +결국 타입스크립트는 더 복잡하고 규모가 큰 프로그램을 **안전하고 정확하게** 만들기 위한 시대적 요구에 의해 탄생했습니다. + +> **💡 강사 메시지** +> "자바스크립트로도 충분하다고 느낄 수 있지만, 타입스크립트는 여러분의 코드를 더 견고하게 만들고 예상치 못한 에러로부터 보호해 주는 **든든한 방패**가 되어줄 것입니다. 이제 그 방패를 어떻게 사용하는지 하나씩 알아봅시다!" + +# 1-1. 자바스크립트의 단점과 타입스크립트 + + 이번에는 **자바스크립트가 가진 구체적인 한계점**이 무엇인지, 그리고 **타입스크립트가 그 한계를 어떻게 멋지게 극복하는지** 알아보겠습니다. + +--- + +## 1. 모든 프로그래밍 언어에는 '타입 시스템'이 있다 + +자바스크립트의 한계를 이해하기 위해 가장 먼저 알아야 할 개념은 바로 **타입 시스템(Type System)**입니다. + +> **타입 시스템이란?** +> 언어에서 사용할 수 있는 값들을 어떤 기준으로 묶어 타입으로 정할지, 그리고 코드의 타입을 **언제, 어떻게 검사할지** 규칙을 모아둔 체계입니다. + +타입 시스템은 크게 두 가지로 나뉩니다. + +| 구분 | 동적 타입 시스템 (Dynamic) | 정적 타입 시스템 (Static) | +| --- | --- | --- | +| **타입 결정 시점** | 코드를 실행할 때(Runtime) | 코드 실행 전(Compile) | +| **유연함** | 매우 자유롭고 유연함 | 엄격하고 고정적임 | +| **대표 언어** | JavaScript, Python | Java, C, C++ | + +--- + +## 2. 동적 타입 시스템 (JavaScript) + +자바스크립트는 변수의 타입을 미리 정하지 않고, 실행 도중에 값에 따라 유동적으로 결정합니다. + +* **장점:** 변수 하나에 문자열을 넣었다가 숫자를 넣는 등 자유롭게 활용할 수 있어 개발 속도가 빠릅니다. +* **단점 (치명적):** 코드 실행 중에 예상치 못한 오류가 발생하여 프로그램이 비정상 종료될 수 있습니다. + +```javascript +let a = "hello"; // string 타입으로 결정 +a = 123; // number 타입으로 변경 (유연함) + +a.toUpperCase(); // ❌ 오류 발생! (숫자에는 사용할 수 없는 메서드) + +``` + +위 코드는 실행은 되지만, 숫자가 들어있는 상태에서 문자열 전용 메서드를 호출하는 순간 프로그램이 멈춰버립니다. 서비스가 운영 중인 상황이라면 아주 치명적인 사고로 이어질 수 있습니다. + +--- + +## 3. 정적 타입 시스템 (Java, C) + +반대로 자바나 C 같은 언어는 실행 전에 모든 변수의 타입을 결정해야 합니다. + +* **장점:** 타입 관련 오류가 있으면 실행조차 되지 않으므로, 개발자가 실수하더라도 미리 확인할 수 있습니다. +* **단점:** 모든 변수에 일일이 타입을 명시해야 해서 코드량이 늘어나고 매우 번거롭습니다. + +--- + +## 4. 타입스크립트의 해답: 점진적 타이핑 (Gradual Typing) + +타입스크립트는 두 시스템의 장점만 합친 독특한 **점진적 타입 시스템(Gradual Type System)**을 사용합니다. + +### ✅ 특징 1. 실행 전 타입 검사 (안전성) + +정적 타입 시스템처럼 프로그램을 실행하기 전에 타입을 검사합니다. 타입 오류가 있다면 미리 빨간 줄로 알려줍니다. + +### ✅ 특징 2. 타입 추론 (유연성) + +모든 변수에 타입을 직접 적지 않아도 됩니다. 변수에 담긴 초기값을 기준으로 타입스크립트가 마치 인공지능처럼 타입을 자동으로 알아냅니다. + +```typescript +// 타입스크립트 코드 +let a = 123; // 타입을 적지 않아도 자동으로 'number'로 추론! + +a.toUpperCase(); // 💡 에러! 실행 전 에디터에서 미리 알려줌 + +``` + +--- + +## 5. 정리하며 + +1. **동적 타입 시스템(JS):** 유연하지만 실행 중에 갑자기 오류가 발생할 수 있는 불안정함이 있습니다. +2. **정적 타입 시스템(Java):** 안정적이지만 모든 타입을 직접 지정해야 하는 불편함이 있습니다. +3. **점진적 타입 시스템(TS):** 실행 전 타입 검사로 **안전성**을 확보하면서도, 자동 타입 추론으로 **유연함**까지 놓치지 않은 멋진 시스템입니다. + +**결론적으로 타입스크립트는 대규모 프로그램을 안정적으로 만들기 위해 자바스크립트에 '타입'이라는 안전장치를 추가한 언어라고 이해하시면 됩니다!** + +![alt text](image-1.png) + +--- + +# 1-2. 타입스크립트의 동작 원리 + +## 0. 도입 (Opening) + +"이번 시간에는 우리가 작성한 타입스크립트 코드가 **내부적으로 어떻게 동작하고, 어떤 과정을 거쳐 컴퓨터에서 실행되는지** 그 원리를 살펴보겠습니다. 이 과정을 이해하면 타입스크립트가 왜 안전한지 그 이유를 명확히 알게 되실 겁니다." + +--- + +## 1. 일반적인 언어의 동작 방식 + +"타입스크립트를 보기 전에, 먼저 대다수의 프로그래밍 언어가 어떻게 실행되는지 알아야 합니다. 우리가 쓰는 언어는 인간 친화적이지만, 컴퓨터는 이진수나 기계어만 이해할 수 있기 때문이죠." + +* **컴파일(Compile):** 우리가 작성한 코드를 컴퓨터가 이해할 수 있는 형태(바이트코드)로 변환하는 과정입니다. +* **컴파일러의 단계:** +1. **AST(추상 문법 트리) 생성:** 코드의 공백, 주석 등을 제거하고 트리 형태의 구조로 코드를 쪼개서 저장합니다. +2. **바이트코드 변환:** AST를 기반으로 실제 실행 가능한 바이트코드를 생성합니다. + +--- + +## 2. 타입스크립트만의 특별한 동작 과정 + +"그럼 타입스크립트는 무엇이 다를까요? 타입스크립트의 컴파일 과정에는 **'안전장치'**가 하나 더 추가되어 있습니다." + +* **타입스크립트의 컴파일 단계:** +1. **AST 변환:** 다른 언어와 동일하게 코드를 트리 구조로 만듭니다. +2. **타입 검사 (Type Check):** **이게 가장 중요합니다.** AST를 보고 코드에 타입 오류가 없는지 확인합니다. 만약 오류가 있다면 여기서 컴파일이 중단됩니다! +3. **자바스크립트 변환:** 타입 검사를 통과하면, AST를 바이트코드가 아닌 **'자바스크립트 코드'**로 변환합니다. + +--- + +## 3. 타입스크립트 컴파일의 결과물 + +"타입스크립트 컴파일 결과로 만들어진 자바스크립트 파일은 어떤 특징을 가질까요?" + +* **검증된 코드:** 타입스크립트가 생성한 JS 파일은 이미 엄격한 타입 검사를 통과한 상태입니다. 따라서 실행 중에 타입 에러가 날 확률이 현저히 낮습니다. +* **타입 코드의 삭제:** 우리가 열심히 작성한 `: number` 같은 타입 관련 문법들은 자바스크립트로 변환될 때 모두 사라집니다. 즉, 실제 프로그램 실행 성능에는 영향을 주지 않고 오직 **'검사용'**으로만 사용되는 것이죠. + +--- + +## 4. 마무리 및 정리 (Closing) + +![alt text](image-2.png) + +> **핵심 요약** +> 1. 일반적인 언어는 **코드 -> AST -> 바이트코드** 순으로 변환됩니다. +> 2. 타입스크립트는 **코드 -> AST -> [타입 검사] -> 자바스크립트** 순으로 변환됩니다. +> 3. 타입 검사를 통과한 안전한 자바스크립트만 실행되므로 훨씬 견고한 프로그램을 만들 수 있습니다. + +"결국 타입스크립트는 우리가 자바스크립트를 실행하기 전에 미리 한 번 꼼꼼하게 검사해주는 **'똑똑한 비서'**와 같다고 생각하시면 됩니다. 자, 원리를 알았으니 이제 직접 코드를 작성해 봐야겠죠? 다음 시간에는 실습 환경을 직접 구축해 보겠습니다. 감사합니다!" + +# 1-3. Hello World : 타입스크립트 첫 실습 + +## 0. 도입 (Opening) + +원리를 이해했으니 이제 직접 몸으로 익힐 차례입니다! 이번 시간에는 **새로운 프로젝트 폴더를 만들고, 타입스크립트 실행에 필요한 도구들을 설치한 뒤, 직접 작성한 코드를 실행**까지 해보겠습니다. 실습 위주의 내용! + +--- + +## 1. 프로젝트 초기화 (Setup) + +"먼저 실습 코드를 보관할 공간을 만들고 Node.js 프로젝트로 선언해 주어야 합니다." + +* **폴더 생성:** `onebite-typescript` 폴더 안에 이번 섹션용 `section1` 폴더 생성 +* **패키지 초기화:** 터미널에서 `npm init` 입력 (모두 Enter를 눌러 기본값으로 설정) +* 이 과정을 거치면 프로젝트의 정보를 담은 `package.json` 파일이 생성됩니다. + +--- + +## 2. 필수 패키지 설치 + +"타입스크립트를 사용하기 위해 꼭 설치해야 하는 두 가지 패키지가 있습니다." + +### ① @types/node 설치 + +```bash +npm i @types/node + +``` + +* **이유:** Node.js가 제공하는 기본 기능(console 등)의 타입을 정의해둔 패키지입니다. +* **중요성:** 타입스크립트는 모든 것에 '타입'이 필요합니다. 이걸 설치하지 않으면 `console` 같은 기본 도구조차 타입이 없다고 에러를 내뱉습니다. + +### ② TypeScript 컴파일러 설치 + +```bash +# Windows +npm i -g typescript +# macOS +sudo npm i -g typescript + +``` + +* **tsc (TypeScript Compiler):** 우리가 쓴 `.ts` 파일을 `.js` 파일로 변환해주는 핵심 도구입니다. `-g` 옵션으로 설치하여 어디서든 사용할 수 있게 합니다. +* **확인:** `tsc -v`를 입력해 버전 정보가 잘 나오는지 확인합니다. + +--- + +## 3. Hello World 작성 및 실행 (전통적 방식) + +"이제 첫 코드를 작성하고, 타입스크립트의 정석적인 실행 과정을 거쳐보겠습니다." + +1. **파일 생성:** `src/index.ts` 파일 생성 및 코드 작성 +```typescript +console.log("Hello TypeScript"); +const a: number = 1; + +``` + +2. **컴파일:** `tsc src/index.ts` 입력 -> `index.js` 파일이 생성됨을 확인 +3. **실행:** `node src/index.js` 입력 -> "Hello TypeScript" 출력 확인 + +--- + +## 4. 더 쉬운 실행 도구: TSX (TypeScript Execute) + +"매번 `tsc`로 변환하고 `node`로 실행하는 건 너무 번거롭죠? 그래서 한 번에 실행해주는 도구를 사용합니다." + +* **tsx 설치:** `npm i -g tsx` +* **장점:** 별도의 `.js` 파일을 생성하지 않고도 타입스크립트 코드를 즉시 실행합니다. +* **실행:** `tsx src/index.ts` +> **참고:** 기존에는 `ts-node`를 많이 썼지만, 최신 Node.js 버전(20 이상)과의 호환성 문제로 인해 본 강의에서는 최신 도구인 **tsx** 사용을 권장합니다. + +--- + +## 5. 마무리 및 정리 (Closing) + +"오늘 우리는 타입스크립트 개발의 기초 공사를 마쳤습니다." + +> **핵심 요약** +> 1. **@types/node**: Node.js 내장 기능을 위한 타입 설명서 +> 2. **tsc**: 타입스크립트를 자바스크립트로 바꾸는 번역기 +> 3. **tsx**: 컴파일과 실행을 한 번에 처리하는 마법 도구 + +"환경 설정은 한 번만 제대로 해두면 앞으로의 학습이 매우 수월해집니다. 자, 이제 도구는 모두 준비되었습니다. 다음 시간에는 이 컴파일러를 우리 입맛에 맞게 설정하는 **컴파일러 옵션**에 대해 배워보겠습니다. 수고하셨습니다!" + + +# 1-4. 타입스크립트 컴파일러 옵션 설정하기 + +## 0. 도입 (Opening) + +이번에는 타입스크립트의 핵심이자 심장이라고 할 수 있는 **컴파일러 옵션**에 대해 알아보겠습니다. 프로젝트의 성격에 맞춰 타입스크립트를 얼마나 엄격하게 사용할지, 어떤 버전의 자바스크립트로 변환할지를 결정하는 아주 중요한 과정입니다. + +--- + +## 1. 컴파일러 옵션이란? + +"컴파일러 옵션은 한마디로 **'컴파일러에게 주는 세부 지시 사항'**입니다." + +* **역할:** 얼마나 엄격하게 검사할 것인지, 결과물의 자바스크립트 버전은 무엇인지 등을 설정합니다. +* **장점:** 프로젝트마다 최적화된 맞춤형 설정을 만들 수 있어 매우 자유롭고 강력합니다. + +--- + +## 2. 컴파일러 옵션 만들기 (`tsconfig.json`) + +"타입스크립트 설정은 프로젝트 루트 폴더의 `tsconfig.json` 파일에서 관리합니다." + +* **자동 생성:** 터미널에 `tsc --init`을 입력하면 기본 설정 파일이 생성됩니다. +* **직접 설정:** 강의에서는 기본 원리를 배우기 위해 자동 생성된 내용을 지우고 `{}` 빈 중괄호부터 하나씩 채워나갈 예정입니다. + +--- + +## 3. 핵심 옵션 살펴보기 + +### ① include + +* **용도:** 컴파일할 파일의 범위를 지정합니다. +* **설정:** `"include": ["src"]` +* **효과:** `tsc` 명령어만 입력해도 `src` 폴더 내의 모든 파일이 한 번에 컴파일됩니다. 일일이 파일명을 입력할 필요가 없어집니다. + +### ② target + +* **용도:** 변환될 자바스크립트의 버전을 설정합니다. +* **설정:** `"target": "ES5"` 또는 `"ESNext"` +* **비교:** `ES5`로 설정하면 최신 문법인 화살표 함수가 일반 함수 표현식으로 변환됩니다. 구형 브라우저 호환성을 챙길 때 유용합니다. + +### ③ module + +* **용도:** 변환될 자바스크립트의 모듈 시스템(import/export 방식)을 설정합니다. +* **설정:** `"module": "CommonJS"` (require 사용) 또는 `"ESNext"` (import 사용) + +### ④ outDir + +* **용도:** 컴파일 결과물(.js)이 저장될 폴더를 지정합니다. +* **설정:** `"outDir": "dist"` +* **효과:** 원본 코드와 결과 코드가 섞이지 않아 프로젝트 구조가 깔끔해집니다. + +### ⑤ strict (매우 중요 ⭐) + +* **용도:** 타입 검사의 엄격함 수준을 결정합니다. +* **설정:** `"strict": true` +* **효과:** 매개변수 타입 정의 등 아주 사소한 부분까지 엄격하게 검사합니다. 타입스크립트의 진가를 느끼려면 반드시 `true`로 설정하는 것이 좋습니다. + +### ⑥ moduleDetection + +* **용도:** 각 파일을 독립된 모듈로 인식하게 합니다. +* **설정:** `"moduleDetection": "force"` +* **효과:** 파일마다 `export {}`를 적지 않아도 변수 이름 중복 오류를 방지할 수 있습니다. + +--- + +## 4. 마무리 및 정리 (Closing) + +"타입스크립트를 우리 입맛에 맞게 길들이는 법을 배웠습니다." + +> **핵심 요약** +> 1. **tsconfig.json**: 타입스크립트 설정의 중심 파일 +> 2. **target/module**: 결과물 자바스크립트의 형태 결정 +> 3. **strict**: 안전한 코딩을 위한 엄격한 검사 모드 활성화 + +"이제 도구 설정까지 모두 완벽하게 마쳤습니다. 다음 시간부터는 본격적으로 타입스크립트의 기본 타입들에 대해 하나씩 파헤쳐 보겠습니다. 고생 많으셨습니다!" \ No newline at end of file diff --git a/typescript/onebite/yujin/ch2.md b/typescript/onebite/yujin/ch2.md new file mode 100644 index 0000000..37fdc65 --- /dev/null +++ b/typescript/onebite/yujin/ch2.md @@ -0,0 +1,680 @@ +# 2-0. 기본 타입이란 + +타입스크립트의 가장 기초가 되는 **[기본 타입]**의 개념을 잡고, 앞으로 섹션 2에서 진행할 **실습 환경**을 구축. + +--- + +## 1. 기본 타입(Basic Types)과 타입 계층도 + +"기본 타입이란 타입스크립트가 우리에게 기본적으로 제공하는 **내장 타입**들을 말합니다." + +![alt text](image-3.png) + +* **다양한 타입 지원:** 우리가 잘 아는 `string`, `number` 같은 원시 타입뿐만 아니라, 타입스크립트에서만 볼 수 있는 `any`, `void`, `never`, `unknown` 같은 특별한 타입들도 포함됩니다. +* **타입 계층도:** 이 타입들은 그냥 흩어져 있는 게 아니라, 부모와 자식 관계를 맺으며 거대한 **계층 구조**를 이루고 있습니다. + +> **강사 메시지:** > "지금 당장 이 계층 구조의 모든 원리를 이해하실 필요는 없습니다! 일단은 **'타입스크립트에는 정말 다양한 도구(타입)들이 있고, 서로 체계적으로 연결되어 있구나'** 정도만 느끼고 넘어가시면 충분합니다. 자세한 관계는 뒤에서 하나씩 파헤쳐 볼 거예요." + +--- + +## 2. 섹션 2 실습 환경 설정하기 + +### ① 프로젝트 초기화 및 패키지 설치 + +1. **폴더 생성:** `onebite-typescript/section2` 폴더를 만들고 VSCode로 엽니다. +2. **패키지 초기화:** `npm init -y` +3. **타입 정의 설치:** `npm i @types/node` (Node.js 내장 기능을 위한 타입 설명서) + +### ② 컴파일러 옵션 설정 (`tsconfig.json`) + +프로젝트 루트에 `tsconfig.json` 파일을 만들고 아래 핵심 옵션들을 설정합니다. + +```json +{ + "compilerOptions": { + "target": "ESNext", // 최신 자바스크립트로 변환 + "module": "ESNext", // 최신 모듈 시스템(ESM) 사용 + "outDir": "dist", // 컴파일 결과물은 dist 폴더에! + "strict": true, // 엄격한 타입 검사 활성화 + "moduleDetection": "force" // 각 파일을 개별 모듈로 취급 + }, + "include": ["src"] +} + +``` + +### ③ 실행 환경 마무리 + +1. **ES 모듈 설정:** `package.json` 파일에 `"type": "module"`을 추가합니다. (tsconfig의 module 옵션과 맞추기 위함) +2. **즉시 실행 설정:** `tsx` 혹은 `ts-node` 사용을 위해 `tsconfig.json` 하단에 옵션을 추가합니다. (강의에서는 최신 도구인 `tsx` 사용을 권장합니다.) + +--- + +## 3. 요약 + +> **핵심 요약** +> 1. **기본 타입**은 타입스크립트가 제공하는 내장 타입이며 계층 구조를 가진다. +> 2. **프로젝트 설정**을 반복하는 이유는 실무에서 언제든 스스로 환경을 구축할 수 있는 개발자가 되기 위해서다. + +# 2-1. 원시 타입과 리터럴 타입 + +타입스크립트의 가장 기본이 되는 **원시 타입**과, 아주 독특한 특징인 **리터럴 타입**의 내용. + +--- + +## 1. 원시 타입 (Primitive Type) 이란? + +"원시 타입은 동시에 **딱 하나의 값만 저장할 수 있는** 가장 기본형 타입입니다." + +* **특징:** 배열이나 객체 같은 비원시 타입과 달리, 숫자면 숫자, 문자면 문자 하나만 담습니다. +* **타입 주석(Type Annotation):** 변수 이름 뒤에 `: 타입`을 붙여 타입을 정의하는 문법입니다. + +--- + +## 2. 5가지 핵심 원시 타입 + +### ① number 타입 + +단순 정수뿐만 아니라 소수, 음수, 특수 숫자까지 모두 포함합니다. + +```typescript +let num1: number = 123; +let num2: number = -123; +let num3: number = 0.123; +let num4: number = Infinity; // 무한대 +let num5: number = NaN; // Not a Number + +``` + +### ② string 타입 + +따옴표 종류에 상관없이 모든 문자열과 템플릿 리터럴을 포함합니다. + +```typescript +let str1: string = "hello"; +let str2: string = `hello ${str1}`; // 템플릿 리터럴 + +``` + +### ③ boolean 타입 + +참(`true`)과 거짓(`false`)만 저장합니다. + +```typescript +let bool1: boolean = true; +let bool2: boolean = false; + +``` + +### ④ null & undefined 타입 + +각각 오직 `null`과 `undefined` 값 하나만 가질 수 있는 타입입니다. + +```typescript +let null1: null = null; +let unde1: undefined = undefined; + +``` + +--- + +## 3. [중요] strictNullChecks (엄격한 null 검사) + +"자바스크립트에서는 변수에 임시로 `null`을 넣어두곤 했죠? 타입스크립트에서는 이게 기본적으로 금지됩니다." + +* **문제:** `let numA: number = null;` ❌ (에러 발생) +* **해결책:** 만약 null 할당을 허용하고 싶다면 `tsconfig.json`에서 `strictNullChecks` 옵션을 `false`로 설정하면 됩니다. +* **권장:** 하지만 안전한 코딩을 위해 이 옵션은 **`true`**로 유지하는 것을 권장합니다. + +--- + +## 4. 리터럴 타입 (Literal Type) + +"리터럴은 우리말로 **'값'**을 의미합니다. 즉, 값 자체가 타입이 되는 아주 특별한 기능입니다." + +```typescript +let numA: 10 = 10; +numA = 11; // ❌ 에러! 10 이외의 값은 넣을 수 없음 + +let strA: "hello" = "hello"; +let boolA: true = true; + +``` + +* **용도:** 특정 변수가 정해진 값만 가져야 할 때(예: 상태 값 등) 매우 유용하게 사용됩니다. + +--- + +## 5. 요약 및 정리 (Closing) + +"오늘 배운 내용을 정리해 볼까요?" + +> **핵심 요약** +> 1. **원시 타입:** `number`, `string`, `boolean`, `null`, `undefined`가 있으며 타입 주석으로 정의한다. +> 2. **strictNullChecks:** `null` 값을 안전하게 다루기 위한 중요한 컴파일러 옵션이다. +> 3. **리터럴 타입:** 값 자체가 타입이 되어, 특정 값만 허용하는 강력한 제약 기능을 제공한다. + +"원시 타입은 모든 타입의 뿌리가 됩니다. 이 기초를 잘 다져두어야 나중에 배울 복잡한 객체나 배열 타입도 쉽게 이해할 수 있습니다." + +# 2-2. 배열과 튜플 + +데이터를 묶어서 관리하는 **배열**과 타입스크립트의 특수한 타입인 **튜플**. + +--- + +## 1. 배열 (Array) + +타입스크립트에서 배열은 자바스크립트의 배열과 유사하지만, **내부에 어떤 타입의 요소들이 들어가는지**를 엄격하게 관리합니다. + +### ① 배열 타입 정의 방법 + +가장 보편적인 방법은 타입 뒤에 `[]`를 붙이는 방식입니다. + +* `let numArr: number[] = [1, 2, 3];` +* `let strArr: string[] = ["hello", "world"];` + +또 다른 방법으로는 **제네릭** 문법을 사용하는 방식이 있습니다. + +* `let boolArr: Array = [true, false];` + +### ② 다양한 타입을 갖는 배열 (Union) + +배열 안에 한 가지 타입이 아닌 여러 타입의 요소를 함께 넣고 싶을 때는 **유니온(|)** 기호를 사용합니다. + +* `let multiArr: (number | string)[] = [1, "hello"];` +* 여기서 `(number | string)[]`는 "숫자나 문자열 중 하나를 요소로 가지는 배열"이라는 뜻입니다. + +### ③ 다차원 배열 + +`[]`를 연달아 작성하여 행렬과 같은 다차원 배열도 쉽게 정의할 수 있습니다. + +* `let doubleArr: number[][] = [[1, 2], [3, 4]];` + +--- + +## 2. 튜플 (Tuple) + +튜플은 자바스크립트에는 없는 타입스크립트만의 특별한 타입으로, **길이와 타입의 순서가 고정된 배열**을 의미합니다. + +### ① 튜플 정의와 특징 + +배열과 비슷해 보이지만, 대괄호(`[]`) 안에 각 인덱스에 들어갈 타입을 직접 명시합니다. + +```typescript +let tup1: [number, number] = [1, 2]; +let tup2: [number, string, boolean] = [1, "hello", true]; + +``` + +* **순서 고정:** 첫 번째 요소는 반드시 숫자, 두 번째는 반드시 문자열이어야 하는 식의 제약이 생깁니다. +* **길이 고정:** 정의된 개수보다 많거나 적은 요소를 할당하려고 하면 에러가 발생합니다. + +### ② 주의사항: 튜플은 결국 배열입니다 + +튜플은 컴파일 후 결국 자바스크립트의 일반 배열로 변환됩니다. 이 때문에 타입스크립트의 시스템상 한계가 존재합니다. + +* **배열 메서드 주의:** `push()`나 `pop()` 같은 메서드를 사용하면 고정된 길이를 무시하고 요소를 추가/삭제할 수 있습니다. +* 타입스크립트가 이 메서드 호출까지는 완벽히 막지 못하므로, 튜플을 사용할 때는 **배열 메서드 사용에 각별히 주의**해야 합니다. + +--- + +## 3. 튜플을 사용하는 이유 + +튜플은 **데이터의 구조와 순서가 중요한 상황**에서 실수를 방지해 줍니다. + +* **예시 (회원 정보 관리):** + +```typescript +// 순서가 어긋나도 자바스크립트는 잡아내지 못함 +const users: [string, number][] = [ + ["이정환", 1], + ["이아무개", 2], + [5, "조아무개"], // ❌ 에러 발생: 순서가 잘못됨(숫자, 문자열 순) +]; + +``` + +이처럼 인덱스마다 정해진 의미가 있는 데이터를 다룰 때, 튜플을 사용하면 동료나 자신의 실수를 컴파일 단계에서 즉시 확인할 수 있습니다. + +--- + +## 💡 요약 + +* **배열:** 같은 타입의 데이터를 유연한 길이로 관리할 때 사용합니다. +* **튜플:** 정해진 개수의 데이터를 특정 순서에 맞게 엄격히 관리해야 할 때 사용합니다. + +# 2-3. 객체 (Object) + +타입스크립트에서 가장 빈번하게 사용되는 데이터 타입 중 하나인 **객체**를 정의하는 방법과 특수한 프로퍼티 문법. + +--- + +## 1. 객체 타입을 정의하는 두 가지 방법 + +### ① `object`로 정의하기 (권장하지 않음) + +단순히 변수의 타입을 `object`라고 선언할 수 있습니다. + +```typescript +let user: object = { + id: 1, + name: "이정환", +}; + +``` + +하지만 이 방식은 큰 문제가 있습니다. `user.id`처럼 점 표기법으로 프로퍼티에 접근하려고 하면 **"object 타입에 id 프로퍼티가 없습니다"**라는 에러가 발생합니다. `object` 타입은 단순히 이 값이 객체라는 정보만 줄 뿐, 그 안에 어떤 상세 프로퍼티가 들어있는지에 대한 정보는 없기 때문입니다. + +### ② 객체 리터럴 타입 (권장) + +객체의 구조를 그대로 타입으로 정의하는 방식입니다. + +```typescript +let user: { + id: number; + name: string; +} = { + id: 1, + name: "이정환", +}; + +``` + +중괄호 내부에 프로퍼티와 그 타입을 직접 나열합니다. 이렇게 하면 객체 내부의 데이터에 자유롭게 접근할 수 있으며, 자동 완성 기능도 완벽하게 지원됩니다. + +> **구조적 타입 시스템 (Property Based Type System)** +> 타입스크립트는 객체의 이름(예: 'Person' 클래스 등)이 아닌, 그 객체가 어떤 프로퍼티들을 가지고 있는지(구조)를 기준으로 타입을 결정합니다. 이를 **구조적 타입 시스템**이라고 부릅니다. + +--- + +## 2. 특수한 프로퍼티 정의하기 + +### ① 선택적 프로퍼티 (Optional Property) + +특정 프로퍼티가 있을 수도 있고 없을 수도 있는 상황일 때 사용합니다. 프로퍼티 이름 뒤에 `?`를 붙여 정의합니다. + +```typescript +let user: { + id?: number; // 있어도 되고 없어도 되는 선택적 프로퍼티 + name: string; +} = { + id: 1, + name: "이정환", +}; + +user = { + name: "홍길동", // id가 없어도 에러가 발생하지 않습니다. +}; + +``` + +* **주의사항:** 프로퍼티를 생략할 수는 있지만, 만약 값을 넣는다면 반드시 지정된 타입(`number`)을 지켜야 합니다. + +### ② 읽기 전용 프로퍼티 (Readonly Property) + +값이 한 번 할당되면 절대 수정할 수 없도록 보호하고 싶을 때 사용합니다. 프로퍼티 이름 앞에 `readonly` 키워드를 붙입니다. + +```typescript +let user: { + id?: number; + readonly name: string; // 수정 불가 +} = { + id: 1, + name: "이정환", +}; + +user.name = "홍길동"; // ❌ 에러 발생: 읽기 전용 프로퍼티는 수정할 수 없습니다. + +``` + +이를 통해 중요한 데이터가 실수로 변경되는 것을 방지할 수 있습니다. + +--- + +## 💡 요약 + +* **객체 리터럴 타입:** 객체의 상세 구조를 정의하며, 실무에서 가장 많이 사용됩니다. +* **선택적 프로퍼티(`?`):** 유연한 객체 구조를 위해 특정 프로퍼티를 생략 가능하게 만듭니다. +* **읽기 전용 프로퍼티(`readonly`):** 데이터의 불변성을 보장하여 의도치 않은 수정을 막습니다. + +# 2-4. 타입 별칭과 인덱스 시그니처 + +타입을 변수처럼 정의해서 재사용하는 **타입 별칭**과, 객체의 구조를 유연하게 정의하는 **인덱스 시그니처**에 대해 알아보겠습니다. + +--- + +## 1. 타입 별칭 (Type Alias) + +타입 별칭을 사용하면 복잡한 타입 정의를 마치 변수처럼 이름을 붙여 따로 관리할 수 있습니다. + +* **정의 방법:** `type 타입_이름 = 타입` 형식으로 작성합니다. +* **장점:** 중복되는 타입 코드를 줄일 수 있고, 코드의 가독성이 좋아집니다. + +```typescript +type User = { + id: number; + name: string; + nickname: string; + location: string; +}; + +let user: User = { + id: 1, + name: "이정환", + nickname: "winterlood", + location: "부천시", +}; + +let user2: User = { + id: 2, + name: "홍길동", + nickname: "hong", + location: "서울시", +}; + +``` + +### 💡 특징 및 주의사항 + +1. **중복 선언 불가:** 동일한 스코프(범위) 내에서 같은 이름의 타입 별칭을 선언할 수 없습니다. +2. **컴파일 후 삭제:** 타입 별칭은 타입스크립트 전용 문법이므로 자바스크립트로 컴파일되면 모두 삭제됩니다. + +--- + +## 2. 인덱스 시그니처 (Index Signature) + +인덱스 시그니처는 객체의 프로퍼티 이름은 모르지만, **key와 value의 타입이 규칙적일 때** 유연하게 타입을 정의하도록 돕는 문법입니다. + +### ① 왜 사용할까? + +만약 국가 코드를 저장하는 객체에 100개의 국가가 들어간다면, 타입을 100줄 적는 것은 매우 비효율적입니다. + +```typescript +// 인덱스 시그니처 사용 전 +type CountryCodes = { + Korea: string; + UnitedState: string; + Brazil: string; + // ... 100개의 국가를 일일이 정의해야 함 +}; + +// 인덱스 시그니처 사용 후 +type CountryCodes = { + [key: string]: string; +}; + +let countryCodes: CountryCodes = { + Korea: "ko", + UnitedState: "us", + Brazil: "bz", +}; + +``` + +* `[key: string]: string`: "key의 타입은 `string`이고, value의 타입도 `string`인 모든 프로퍼티를 허용한다"는 의미입니다. + +### ② 필수 프로퍼티와 함께 사용하기 + +인덱스 시그니처를 사용하면서 특정 프로퍼티를 반드시 포함하도록 강제할 수도 있습니다. + +```typescript +type CountryNumberCodes = { + [key: string]: number; + Korea: number; // Korea 프로퍼티는 반드시 있어야 함 +}; + +``` + +> **⚠️ 주의사항** +> 인덱스 시그니처를 사용하면서 추가 프로퍼티를 정의할 때, 추가 프로퍼티의 value 타입은 인덱스 시그니처의 value 타입과 **일치하거나 호환**되어야 합니다. +> ```typescript +> type CountryNumberCodes = { +> [key: string]: number; +> Korea: string; // ❌ 에러: 인덱스 시그니처의 value가 number이므로 string은 올 수 없음 +> }; +> +> ``` + +--- + +## 💡 요약 + +* **타입 별칭:** 복잡한 객체나 타입을 별도의 이름으로 정의하여 **재사용성**을 높입니다. +* **인덱스 시그니처:** 규칙적인 구조를 가진 객체의 타입을 **간결하고 유연하게** 정의할 때 사용합니다. + +# 2-5. 열거형(Enum) 타입 + +자바스크립트에는 없지만, 타입스크립트에서 매우 유용하게 쓰이는 **열거형(Enum)** 타입. + +--- + +## 1. 열거형(Enum) 타입이란? + +열거형은 여러 개의 연관된 값들을 나열하고, 각각에 이름을 부여하여 관리하는 타입입니다. 주로 유저 권한, 국가 코드, 방향 등 정해진 선택지 안에서 값을 할당해야 할 때 사용합니다. + +--- + +## 2. 숫자형 열거형 (Numeric Enum) + +가장 기본이 되는 형태이며, 각 멤버에 숫자 값을 할당합니다. + +```typescript +enum Role { + ADMIN = 0, + USER = 1, + GUEST = 2, +} + +const user1 = { name: "이정환", role: Role.ADMIN }; // 0 +const user2 = { name: "홍길동", role: Role.USER }; // 1 + +``` + +### 💡 숫자형 Enum의 특징: 자동 할당 + +멤버에 숫자를 직접 할당하지 않아도 **0부터 1씩 늘어나는 값**이 자동으로 부여됩니다. 시작 값을 지정하면 그 뒤의 값들은 자동으로 1씩 증가합니다. + +* **기본:** `ADMIN(0) → USER(1) → GUEST(2)` +* **시작 값 지정 시:** `ADMIN(10) → USER(11) → GUEST(12)` + +--- + +## 3. 문자열 열거형 (String Enum) + +멤버에 숫자 대신 **문자열 값**을 할당하는 방식입니다. + +```typescript +enum Language { + korean = "ko", + english = "en", +} + +const user1 = { + name: "이정환", + language: Language.korean, // "ko" +}; + +``` + +### ✅ 문자열 Enum의 장점 + +단순히 `"ko"`라고 직접 적는 대신 `Language.korean`을 사용하면 **오타를 방지**할 수 있고, 코드의 의미가 훨씬 더 명확해집니다. + +--- + +## 4. Enum의 특별한 점: 컴파일 결과 + +일반적인 타입들은 컴파일 후 자바스크립트에서 모두 사라지지만, **Enum은 사라지지 않고 자바스크립트 객체로 변환됩니다.** + +이런 특징 덕분에 컴파일 이후에도 실제 실행 환경에서 `Role.ADMIN`과 같이 **값으로서 호출하여 사용**할 수 있는 것입니다. + +--- + +## 💡 요약 + +* **Enum:** 여러 값에 이름을 붙여 열거하고 관리하는 타입스크립트 전용 문법입니다. +* **숫자형 Enum:** 0부터 자동 할당되거나 특정 숫자부터 1씩 증가합니다. +* **문자열 Enum:** 명확한 문자열 값을 할당하여 오타를 방지하고 가독성을 높입니다. +* **런타임 존재:** 다른 타입과 달리 컴파일 후에도 객체 형태로 남아 실제 값으로 쓰입니다. + +--- + +# 2-6. Any와 Unknown 타입 + +타입스크립트의 타입 검사를 무력화하는 **Any** 타입과, 그 대안으로 사용할 수 있는 더 안전한 **Unknown** 타입. + +--- + +## 1. Any 타입 (모든 검사를 해제하는 치트키) + +`any` 타입은 타입스크립트의 가장 큰 특징인 **타입 검사를 받지 않도록** 만드는 특수한 타입입니다. + +### ① 특징 + +* **모든 값 할당 가능:** 숫자, 문자열, 불리언, 객체 등 어떤 타입의 값도 담을 수 있습니다. +* **모든 곳에 할당 가능:** `any` 타입의 값은 다른 타입으로 정의된 변수에도 자유롭게 할당됩니다. +* **메서드 사용 제한 없음:** 해당 값이 실제로 가지고 있지 않은 메서드(`toUpperCase`, `toFixed` 등)를 호출해도 컴파일 에러가 발생하지 않습니다. + +```typescript +let anyVar: any = 10; +anyVar = "hello"; // 에러 발생 안 함 + +let num: number = 20; +num = anyVar; // any 타입은 어디든 들어갈 수 있음 + +``` + +### ⚠️ 위험성 (사용 자제 권장) + +`any`를 남용하면 타입스크립트가 제공하는 안전장치를 모두 스스로 버리는 것과 같습니다. 컴파일 시점에는 조용하다가 **실제 프로그램이 실행되는 도중(Runtime)**에 에러가 터지게 됩니다. 정말 어쩔 수 없는 경우를 제외하고는 사용하지 않는 것이 좋습니다. + +--- + +## 2. Unknown 타입 (안전한 전체 타입) + +`unknown` 타입은 `any`처럼 모든 값을 담을 수 있지만, 그 값을 사용하는 방식은 훨씬 엄격하고 안전합니다. + +### ① 특징 + +* **모든 값 할당 가능:** `any`와 마찬가지로 어떤 값이든 변수에 저장할 수 있습니다. +* **할당 및 사용 제한:** `unknown` 타입의 값을 다른 타입의 변수에 할당하거나, 연산에 참여시키거나, 메서드를 호출하는 것이 **기본적으로 불가능**합니다. + +```typescript +let unknownVar: unknown; +unknownVar = 123; +unknownVar = "string"; + +let num: number = unknownVar; // ❌ 에러: unknown은 다른 곳에 바로 할당 불가 +unknownVar * 2; // ❌ 에러: 연산 불가 + +``` + +### ② 안전하게 사용하기 (타입 좁히기) + +`unknown` 변수의 값을 실제로 사용하려면, **조건문** 등을 통해 그 값이 특정 타입임을 확실히 증명해야 합니다. + +```typescript +if (typeof unknownVar === "number") { + // 이 블록 안에서는 unknownVar가 number 타입으로 안전하게 인정됩니다. + console.log(unknownVar * 2); +} + +``` + +--- + +## 💡 요약 및 비교 + +| 특징 | Any | Unknown | +| --- | --- | --- | +| **모든 값 저장 가능** | ✅ 가능 | ✅ 가능 | +| **다른 타입 변수에 할당** | ✅ 가능 (위험) | ❌ 불가능 | +| **연산 및 메서드 호출** | ✅ 가능 (위험) | ❌ 불가능 (타입 확인 필수) | +| **안전성** | ❌ 매우 낮음 | ✅ 높음 | + +**결론적으로, 당장 어떤 값이 들어올지 몰라 범용적인 타입이 필요하다면 `any`보다는 `unknown`을 사용하는 것이 타입스크립트다운 안전한 코딩 방식.** + +# 2-7. Void와 Never 타입 + +'아무것도 없음'을 의미하는 **Void**와 '발생할 수 없음'을 의미하는 **Never** 타입. + +--- + +## 1. Void 타입 + +`void` 타입은 **"아무런 값도 반환하지 않음"**을 의미합니다. 주로 함수의 반환 타입으로 사용됩니다. + +### ① 함수의 반환 타입으로 사용 + +함수 내부에서 `return` 문이 없거나, 명시적으로 값을 반환하지 않을 때 사용합니다. + +```typescript +function func2(): void { + console.log("hello"); + // return이 없으므로 반환값은 undefined이나, 타입은 void로 정의합니다. +} + +``` + +### ② 변수의 타입으로 사용 + +`void` 타입으로 선언된 변수에는 오직 `undefined`만 담을 수 있습니다. + +* **strictNullChecks: true (기본):** `undefined`만 허용 +* **strictNullChecks: false:** `undefined`와 `null` 모두 허용 + +```typescript +let a: void; +a = undefined; // ✅ 가능 +a = 1; // ❌ 에러 + +``` + +--- + +## 2. Never 타입 + +`never` 타입은 **"불가능"**을 의미합니다. 어떠한 값도 가질 수 없고, 반환될 수도 없는 상태를 나타냅니다. + +### ① 함수의 반환 타입으로 사용 + +함수가 정상적으로 종료되지 않아 **아무런 값도 반환할 수 없는 상황**일 때 사용합니다. + +* **무한 루프:** 함수가 영원히 끝나지 않아 반환이 불가능한 경우 +* **예외 발생:** `throw`를 통해 의도적으로 오류를 던져 함수를 중단시키는 경우 + +```typescript +// 무한 루프 +function func3(): never { + while (true) {} +} + +// 의도적인 에러 발생 +function func4(): never { + throw new Error(); +} + +``` + +### ② 변수의 타입으로 사용 (철저한 고립) + +`never` 타입으로 선언된 변수에는 **그 어떠한 값도 할당할 수 없습니다.** 심지어 모든 타입을 받아주는 `any` 타입의 값조차도 `never` 타입 변수에는 들어갈 수 없습니다. + +```typescript +let a: never; +a = 1; // ❌ 에러 +a = null; // ❌ 에러 +a = undefined; // ❌ 에러 +a = anyVar; // ❌ 에러 + +``` + +--- + +## 💡 요약 및 비교 + +| 특징 | Void | Never | +| --- | --- | --- | +| **의미** | 아무런 값도 반환하지 않음 | 반환하는 것 자체가 불가능함 | +| **주요 용도** | 일반적인 `return` 없는 함수 | 무한 루프, 에러 던지는 함수 | +| **허용 값** | `undefined` (옵션에 따라 `null`) | **없음** (그 어떤 값도 불가) | \ No newline at end of file diff --git a/typescript/onebite/yujin/ch3.md b/typescript/onebite/yujin/ch3.md new file mode 100644 index 0000000..483dab9 --- /dev/null +++ b/typescript/onebite/yujin/ch3.md @@ -0,0 +1,489 @@ +# 3-0. 타입스크립트를 이해한다는 것은? + +단순히 문법을 익히는 단계를 넘어, 타입스크립트의 **원리와 동작 방식** + +--- + +## 1. 타입스크립트의 '원리'가 왜 중요한가? + +"문법만 빨리 배워서 프로젝트에 적용하면 안 되나요?"라는 의문이 들 수 있습니다. 하지만 타입스크립트는 단순히 외워서 써먹기에는 생각보다 만만치 않은 언어입니다. + +* **응용력의 한계:** 공식 문서의 치트시트만으로는 실무에서 마주치는 복잡하고 예외적인 상황들을 해결하기 어렵습니다. +* **복잡한 타입의 벽:** 강의 후반부(10섹션)에서 다룰 아래와 같은 코드를 보면 원리 이해의 중요성을 실감할 수 있습니다. + +```typescript +type ReturnType any> = T extends ( + ...args: any +) => infer R + ? R + : never; + +``` + +원리에 대한 이해 없이 위와 같은 조건부 타입(Conditional Types)이나 추론(infer) 문법을 단순히 암기해서 사용하는 것은 거의 불가능에 가깝습니다. + +--- + +## 2. 원리를 모를 때 발생하는 문제 (강사의 경험담) + +강사인 저 역시 초보 시절, 빠른 적용을 위해 문법만 외워 프로젝트에 투입된 적이 있습니다. 그 결과는 다음과 같았습니다. + +1. **더티 코드 생산:** 타입스크립트가 지적하는 수많은 오류를 근본적으로 해결하지 못해, 이를 회피하기 위한 임시방편의 코드를 남발하게 되었습니다. +2. **개발 기간 연장:** 오류를 해결하는 데 더 많은 시간을 쏟게 되어 오히려 생산성이 떨어졌습니다. +3. **학습의 회귀:** 결국 원점으로 돌아와 기초 원리부터 다시 공부해야만 했습니다. + +--- + +## 3. 이번 섹션에서 배울 핵심 내용 + +단순한 'How(어떻게 쓰는가)'를 넘어 **'Why(왜 그렇게 동작하는가)'**에 집중합니다. + +* **타입 정의의 기준:** 타입스크립트가 타입을 판단하는 근거 +* **타입 간의 관계:** 어떤 타입이 다른 타입의 부모나 자식이 되는 기준 +* **오류 검사의 원리:** 타입스크립트가 코드의 안정성을 검사하는 내부 메커니즘 + +--- + +## 💡 요약 + +타입스크립트를 제대로 이해한다는 것은 **"타입스크립트가 세상을 바라보는 규칙"**을 익히는 과정입니다. 이번 섹션을 통해 어떤 복잡한 타입을 만나더라도 능동적으로 해결할 수 있는 탄탄한 기초 체력을 길러보겠습니다. + +# 3-1. 타입은 집합이다 + +타입스크립트의 가장 핵심적인 원리 중 하나는 **'타입을 집합으로 이해하는 것'**입니다. 이 개념을 잡아야만 앞으로 배울 복잡한 오류와 동작 방식을 명확히 이해할 수 있습니다. + +![alt text](image-4.png) + +--- + +## 1. 타입과 집합의 관계 + +집합이란 동일한 속성을 가진 요소들을 하나로 묶은 단위를 말합니다. 타입스크립트의 타입 역시 이와 같습니다. + +* **거대 집합 (`number` 타입):** 모든 숫자 값들을 포함하는 아주 큰 집합입니다. +* **부분 집합 (`Number Literal` 타입):** 예를 들어 `20`이라는 리터럴 타입은 오직 숫자 `20` 하나만 포함하는 아주 작은 집합입니다. +* **포함 관계:** 숫자 `20`은 리터럴 타입의 원소이기도 하지만, 동시에 `number`라는 거대 집합에도 속합니다. 즉, **모든 리터럴 타입은 해당 원시 타입의 부분 집합**입니다. + +--- + +## 2. 슈퍼 타입과 서브 타입 + +타입 간의 포함 관계를 부르는 명칭이 있습니다. + +* **슈퍼 타입 (Super Type):** 다른 타입을 포함하는 타입 (부모 타입) +* **서브 타입 (Sub Type):** 다른 타입에 포함되는 타입 (자식 타입) + +우리가 이전에 보았던 **타입 계층도**는 사실 이 슈퍼 타입과 서브 타입의 관계를 지도처럼 그려놓은 것입니다. + +--- + +## 3. 타입 호환성 (Type Compatibility) + +타입 호환성이란 **어떤 타입의 값을 다른 타입으로 취급해도 괜찮은지** 판단하는 규칙입니다. + +### ① 업 캐스팅 (Upcasting) + +* **의미:** 서브 타입의 값을 슈퍼 타입의 값으로 취급하는 것 (작은 쪽 → 큰 쪽) +* **가능 여부:** **언제나 가능합니다.** +* **비유:** "정사각형은 직사각형이다"라고 말하는 것과 같습니다. + +### ② 다운 캐스팅 (Downcasting) + +* **의미:** 슈퍼 타입의 값을 서브 타입의 값으로 취급하는 것 (큰 쪽 → 작은 쪽) +* **가능 여부:** **대부분의 상황에서 불가능합니다.** +* **비유:** "직사각형은 정사각형이다"라고 말할 수 없는 것과 같습니다. + +--- + +## 4. 코드로 보는 호환성 + +집합 관계를 코드로 직접 확인해 보겠습니다. + +```typescript +let num1: number = 10; // 슈퍼 타입 (number) +let num2: 10 = 10; // 서브 타입 (Number Literal 10) + +// ✅ 업 캐스팅: 서브 타입을 슈퍼 타입에 할당 (허용) +num1 = num2; + +// ❌ 다운 캐스팅: 슈퍼 타입을 서브 타입에 할당 (금지) +num2 = num1; + +``` + +### 왜 다운 캐스팅은 안 될까? + +`num1`은 `number` 타입이므로 나중에 `10`이 아닌 `100`, `-5` 등 어떤 숫자든 들어올 가능성이 있습니다. 반면 `num2`는 오직 `10`만 받아낼 수 있는 아주 좁은 통입니다. 따라서 넓은 범위의 값을 좁은 범위의 변수에 억지로 넣으려고 하면 문제가 발생할 수밖에 없기 때문에 타입스크립트는 이를 사전에 차단합니다. + +--- + +## 💡 요약 + +* 타입스크립트의 타입은 **값들의 집합**이다. +* **업 캐스팅(서브 → 슈퍼)**은 자유롭게 허용된다. +* **다운 캐스팅(슈퍼 → 서브)**은 데이터의 안전성을 위해 원칙적으로 금지된다. + + +# 3-2. 타입 계층도와 함께 기본 타입 살펴보기 + +이전 단원의 '집합'의 개념을 토대로 타입 계층도를 다시 살펴보면, 각 타입이 왜 특정한 동작 방식을 갖는지 명확히 이해할 수 있습니다. + +![alt text](image-5.png) + +--- + +## 1. unknown 타입 (전체 집합) + +`unknown` 타입은 타입 계층도의 최상단에 위치하는 **전체 집합**입니다. + +* **슈퍼 타입:** 모든 타입의 부모입니다. 따라서 어떤 타입의 값이든 `unknown` 타입 변수에 담는 것은 **업 캐스팅**이 되어 항상 허용됩니다. +* **제약:** 반대로 `unknown` 타입의 값을 다른 타입의 변수에 담는 것은 **다운 캐스팅**이므로, `any` 타입을 제외하고는 모두 금지됩니다. + +--- + +## 2. never 타입 (공집합) + +`never` 타입은 계층도의 가장 바닥에 위치하는 **공집합**입니다. + +* **의미:** 아무것도 포함하지 않는 집합입니다. 무한 루프나 예외 발생처럼 값을 반환하는 것 자체가 불가능한 상황에서 사용됩니다. +* **서브 타입:** 공집합은 모든 집합의 부분 집합이듯, `never`는 모든 타입의 자식입니다. 따라서 `never` 타입의 값은 어떤 타입의 변수에도 할당(업 캐스팅)할 수 있습니다. +* **제약:** 하지만 그 어떤 타입의 값도 `never` 타입 변수에는 담을 수 없습니다. (공집합에 원소를 넣는 다운 캐스팅은 불가능하기 때문입니다.) + +--- + +## 3. void 타입 + +`void` 타입은 아무것도 반환하지 않는 함수의 반환값 타입으로 쓰이며, 계층도상에서 `undefined`를 자식으로 둡니다. + +* **업 캐스팅:** `undefined` 타입은 `void`의 서브 타입입니다. 따라서 `void`로 선언된 함수에서 `undefined`를 반환하거나 아무것도 적지 않는 것은 허용됩니다. +* **관계:** `void` 타입의 변수에는 오직 `undefined`와 `never` 타입의 값만 할당할 수 있습니다. + +--- + +## 4. any 타입 (치트키) + +`any`는 타입 계층도와 집합의 논리를 **완전히 무시하는 예외적인 타입**입니다. + +* **쌍방향 호환:** 모든 타입의 슈퍼 타입이 될 수도 있고, 동시에 모든 타입의 서브 타입이 될 수도 있습니다. +* **위험성:** `any` 타입의 값을 다른 변수에 담는 것은 논리적으로 '다운 캐스팅'임에도 불구하고 타입스크립트가 이를 허용합니다. 이 때문에 안정성이 깨질 수 있으므로 사용에 주의해야 합니다. +* **유일한 예외:** 단 하나, `never` 타입만큼은 `any` 조차도 침범할 수 없습니다. `never`는 공집합이므로 그 어떤 값도 담을 수 없기 때문입니다. + +--- + +## 💡 요약 + +* **unknown:** 모든 것을 담을 수 있는 **가장 큰 주머니** +* **never:** 아무것도 담을 수 없는 **빈 주머니** (모든 타입의 자식) +* **void:** `undefined`를 포함하는 **상위 타입** +* **any:** 타입 시스템의 **규칙 파괴자** + +# 3-3. 객체 타입의 호환성 + +기본 타입과 마찬가지로 객체 타입 사이에도 **슈퍼-서브 타입 관계**가 존재하며, 이를 통해 호환성 여부를 판단합니다. 객체 타입의 호환성을 결정하는 핵심 기준을 정리. + +--- + +## 1. 객체 타입의 슈퍼-서브 관계 + +객체 타입 간의 호환성은 어떤 타입이 더 많은 프로퍼티를 가졌느냐가 아니라, **어떤 타입의 조건이 더 적고 일반적이냐**에 따라 결정됩니다. + +### ① 프로퍼티가 적은 쪽이 슈퍼 타입이다 + +언뜻 생각하면 프로퍼티가 많은 타입이 '더 크다'고 느낄 수 있지만, 집합의 관점에서는 반대입니다. + +* **Animal (슈퍼 타입):** `name`과 `color`만 있으면 모두 포함 (범위가 넓음) +* **Dog (서브 타입):** `name`, `color`에 추가로 `breed`까지 있어야 포함 (조건이 까다로워 범위가 좁음) + +```typescript +type Animal = { + name: string; + color: string; +}; + +type Dog = { + name: string; + color: string; + breed: string; +}; + +let animal: Animal = { name: "기린", color: "yellow" }; +let dog: Dog = { name: "돌돌이", color: "brown", breed: "진도" }; + +animal = dog; // ✅ 업 캐스팅 (허용) +dog = animal; // ❌ 다운 캐스팅 (금지) + +``` + +--- + +## 2. 구조적 타입 시스템의 적용 + +타입스크립트는 **구조적 타입 시스템**을 따르기 때문에, 객체가 가진 프로퍼티의 구조만 맞으면 슈퍼-서브 관계가 성립합니다. `Dog`는 `Animal`이 갖춰야 할 모든 조건(`name`, `color`)을 이미 만족하고 있으므로, `Animal` 타입에 포함될 수 있는 것입니다. + +--- + +## 3. 초과 프로퍼티 검사 (Excess Property Check) + +객체 타입의 호환성 원칙(업 캐스팅 허용)을 따르더라도, **객체 리터럴**을 직접 사용할 때는 타입스크립트의 특수한 검사가 발동합니다. + +### ① 검사의 목적 + +변수를 객체 리터럴로 **직접 초기화**할 때, 타입 정의에 없는 프로퍼티가 포함되어 있으면 "실수했을 가능성이 높다"고 판단하여 오류를 발생시킵니다. + +```typescript +type Book = { + name: string; + price: number; +}; + +// ❌ 오류 발생 (초과 프로퍼티 검사) +let book2: Book = { + name: "한 입 크기로 잘라먹는 리액트", + price: 33000, + skill: "reactjs", // Book 타입에 정의되지 않은 프로퍼티 +}; + +``` + +### ② 검사를 피하는 방법 + +이 검사는 오직 **객체 리터럴을 변수에 직접 할당할 때**만 일어납니다. 미리 선언된 다른 변수를 할당하면 초과 프로퍼티 검사가 작동하지 않고 순수한 '타입 호환성' 원칙만 적용됩니다. + +```typescript +let programmingBook = { + name: "한 입 크기로 잘라먹는 리액트", + price: 33000, + skill: "reactjs", +}; + +let book3: Book = programmingBook; // ✅ 허용 (업 캐스팅으로 인식) + +``` + +--- + +## 💡 요약 + +1. **객체 타입의 호환성:** 조건(프로퍼티)이 더 적은 타입이 **슈퍼 타입**이 됩니다. +2. **업 캐스팅:** 프로퍼티가 많은 객체를 프로퍼티가 적은 타입의 변수에 담는 것은 가능합니다. +3. **초과 프로퍼티 검사:** 객체 리터럴로 직접 값을 넣을 때는 정의된 프로퍼티만 딱 맞게 넣어야 합니다. (실수 방지 목적) + +# 3-4. 대수 타입 (Algebraic Type) + +대수 타입이란 여러 개의 타입을 합성해서 만드는 타입을 말합니다. 여기에는 두 가지 이상의 타입을 합치는 **합집합(Union)**과 공통된 속성을 추출하는 **교집합(Intersection)** 타입이 존재합니다. + +![alt text](image-6.png) + +--- + +## 1. 합집합 타입 (Union Type) + +유니온 타입은 바(`|`) 기호를 사용하여 정의하며, 여러 타입 중 하나라도 만족하면 허용되는 타입입니다. + +* **기본 타입의 유니온:** +```typescript +let a: string | number | boolean; +a = 1; // ✅ OK +a = "hello"; // ✅ OK +a = true; // ✅ OK + +``` + +* **객체 타입의 유니온:** +객체 타입의 유니온은 각 타입의 프로퍼티 조건을 **최소 하나 이상 완전히 만족**하는 객체들의 집합입니다. +```typescript +type Dog = { name: string; color: string; }; +type Person = { name: string; language: string; }; +type Union1 = Dog | Person; + +let union1: Union1 = { name: "강아지", color: "white" }; // ✅ Dog 조건 만족 +let union2: Union1 = { name: "사람", language: "ko" }; // ✅ Person 조건 만족 +let union3: Union1 = { name: "혼종", color: "black", language: "en" }; // ✅ 둘 다 만족 + +let union4: Union1 = { name: "이름만" }; // ❌ Dog도 Person도 아니므로 에러 + +``` + +--- + +## 2. 교집합 타입 (Intersection Type) + +인터섹션 타입은 앰퍼샌드(`&`) 기호를 사용하여 정의하며, 나열된 모든 타입을 **동시에 만족**해야 하는 타입입니다. + +* **기본 타입의 인터섹션:** +대부분의 기본 타입(string, number 등)은 서로 겹치는 값이 없으므로, 인터섹션을 수행하면 아무것도 담을 수 없는 공집합 타입인 **never**로 추론됩니다. +```typescript +let variable: number & string; // never 타입 + +``` + +* **객체 타입의 인터섹션:** +객체 타입에서 인터섹션은 **모든 프로퍼티를 합친 것과 같은** 효과를 냅니다. 모든 타입의 조건을 동시에 충족해야 하기 때문입니다. +```typescript +type Dog = { name: string; color: string; }; +type Person = { name: string; language: string; }; +type Intersection = Dog & Person; + +let intersection1: Intersection = { + name: "캡틴 도그", + color: "gold", + language: "Korean" // 모든 프로퍼티가 다 있어야만 합니다. +}; + +``` +--- + +## 💡 요약 및 비교 + +| 타입 종류 | 기호 | 의미 | 객체 관점 | +| --- | --- | --- | --- | +| **Union** | `|` | 합집합 | 나열된 타입 중 **하나라도** 온전히 만족하면 허용 | +| **Intersection** | `&` | 교집합 | 나열된 **모든 타입의 프로퍼티**를 전부 가져야 허용 | + +## 3-5. 타입 추론 (Type Inference) + +타입스크립트는 프로그래머가 모든 변수에 타입을 직접 명시하지 않아도, 코드를 해석하여 타입을 자동으로 결정하는 **타입 추론** 기능을 제공합니다. + +--- + +### 1. 타입 추론이 가능한 주요 상황 + +타입스크립트는 주로 **대입 연산자의 오른쪽 값(초기값)**이나 **코드의 문맥**을 살펴보고 타입을 결정합니다. + +* **일반 변수 선언:** 초기값을 기준으로 가장 적절한 타입이 추론됩니다. 객체의 경우 내부 프로퍼티의 구조까지 파악하여 복잡한 객체 리터럴 타입으로 추론합니다. +* **구조 분해 할당:** 배열이나 객체에서 값을 꺼내올 때도 원본의 타입을 추적하여 자동으로 할당합니다. +* **함수의 반환값:** 함수 내부의 `return` 문 뒤에 오는 값을 보고 해당 함수의 반환 타입을 결정합니다. +* **기본값이 설정된 매개변수:** 매개변수에 기본값을 설정하면, 그 값을 기준으로 매개변수의 타입이 정해집니다. + +--- + +### 2. 주의해야 할 추론 방식 + +추론 방식은 변수 선언 방식(`let`, `const`)이나 초기화 여부에 따라 달라집니다. + +#### ① any 타입의 진화 (Evolution) + +변수를 선언할 때 초기값을 생략하면 **암시적 any** 타입이 됩니다. 일반적인 `any`와 달리, 이 변수는 **어떤 값을 할당하느냐에 따라 타입이 계속해서 변합니다.** + +```typescript +let d; // 암시적 any +d = 10; // 이 시점부터 number 타입처럼 동작 +d.toFixed(); + +d = "hello"; // 이 시점부터 string 타입처럼 동작 +d.toUpperCase(); + +``` + +* **위험성:** 타입이 유동적으로 변하므로 예상치 못한 에러를 유발할 수 있습니다. 가급적 선언 시 초기값을 주거나 명시적으로 타입을 선언하는 것이 좋습니다. + +#### ② const 상수의 추론 + +`let` 변수는 값이 바뀔 수 있으므로 `number`나 `string` 같은 범용적인 타입으로 추론되는 반면, `const` 상수는 값이 절대 변하지 않으므로 **리터럴 타입**으로 가장 좁게 추론됩니다. + +* `let a = 10;` → `number` 타입 +* `const b = 10;` → `10` (리터럴) 타입 + +--- + +### 3. 최적 공통 타입 (Best Common Type) + +배열에 여러 종류의 타입이 섞여 있을 경우, 타입스크립트는 모든 요소를 포괄할 수 있는 가장 적절한 타입을 선택합니다. 보통 **유니온(Union)** 타입으로 추론됩니다. + +```typescript +let arr = [1, "string"]; +// number와 string이 섞여 있으므로 (number | string)[] 타입으로 추론 + +``` + +--- + +## 💡 요약 + +1. **편의성:** 타입 추론 덕분에 모든 곳에 타입 주석을 달 필요가 없어 코드가 간결해집니다. +2. **한계:** 함수의 매개변수 등 문맥만으로 알 수 없는 곳은 추론이 불가능하므로 직접 명시해야 합니다. +3. **안전성:** 암시적 `any`가 진화하는 상황은 에러의 원인이 될 수 있으므로 주의가 필요합니다. + +## 3-6. 타입 단언 (Type Assertion) + +타입스크립트가 코드를 분석해 타입을 추론하는 것이 원칙이지만, 때로는 개발자가 해당 값의 타입을 시스템보다 더 정확히 알고 있는 경우가 있습니다. 이럴 때 **"이 값의 타입은 이것이니 의심하지 마라"**고 타입스크립트에게 알려주는 기능을 **타입 단언**이라고 합니다. + +--- + +### 1. 타입 단언의 사용법 + +가장 보편적인 방법은 `값 as 타입` 문법을 사용하는 것입니다. + +* **초기화 시 빈 객체 사용:** 특정 타입으로 정의된 변수를 빈 객체로 초기화하고 나중에 값을 채우고 싶을 때 유용합니다. +* **초과 프로퍼티 검사 회피:** 타입에 정의되지 않은 속성이 포함되어 있어도 단언을 통해 강제로 할당할 수 있습니다. + +```typescript +type Person = { name: string; age: number; }; + +// 💡 빈 객체를 Person 타입으로 단언 +let person = {} as Person; +person.name = "이정환"; +person.age = 23; + +``` + +--- + +### 2. 타입 단언의 성립 조건 + +무분별한 단언을 막기 위해 타입스크립트는 최소한의 안전장치를 둡니다. `A as B`라고 할 때, 다음 중 하나는 만족해야 합니다. + +1. **A가 B의 슈퍼타입이다.** (큰 주머니 → 작은 주머니로 단언) +2. **A가 B의 서브타입이다.** (작은 주머니 → 큰 주머니로 단언) + +* **✅ 가능:** `10 as unknown` (number는 unknown의 서브타입) +* **❌ 불가능:** `10 as string` (둘은 아무런 상속 관계가 없음) + +--- + +### 3. 특수한 단언 기법 + +#### ① 다중 단언 (Double Assertion) + +서로 상관없는 타입을 단언하고 싶을 때 `unknown`을 거쳐서 단언할 수 있습니다. 하지만 이는 타입 시스템을 완전히 무력화하는 위험한 방식이므로 권장되지 않습니다. + +```typescript +// ⚠️ 매우 위험한 방식 +let num = 10 as unknown as string; + +``` + +#### ② const 단언 + +값 뒤에 `as const`를 붙이면 해당 값을 **가장 좁은 리터럴 타입**으로 고정합니다. 특히 객체에 사용할 경우 모든 프로퍼티가 자동으로 `readonly`가 되어 변경이 불가능해집니다. + +```typescript +let cat = { + name: "야옹이", + color: "yellow", +} as const; + +cat.name = "나비"; // ❌ 에러: 모든 프로퍼티가 읽기 전용임 + +``` + +#### ③ Non-Null 단언 (`!`) + +값 뒤에 느낌표(`!`)를 붙이면, 타입스크립트에게 **"이 값은 절대 null이나 undefined가 아니다"**라고 단언하는 것입니다. 선택적 프로퍼티를 다룰 때 자주 사용됩니다. + +```typescript +type Post = { title: string; author?: string; }; +let post: Post = { title: "게시글1" }; + +// author가 없을 수도 있지만, 무조건 있다고 단언함 +const len: number = post.author!.length; + +``` + +--- + +## 💡 요약 및 주의사항 + +1. **타입 단언**은 실제 값을 바꾸는 것이 아니라, 타입스크립트의 **눈을 잠시 가리는 것**입니다. +2. 잘못된 단언은 컴파일 에러는 없애주지만, **런타임 에러(실제 실행 중 오류)**의 주범이 됩니다. +3. 따라서 가급적 타입 추론을 믿되, 정말 확실한 상황에서만 조심스럽게 사용해야 합니다. diff --git a/typescript/onebite/yujin/image-1.png b/typescript/onebite/yujin/image-1.png new file mode 100644 index 0000000..f7b132b Binary files /dev/null and b/typescript/onebite/yujin/image-1.png differ diff --git a/typescript/onebite/yujin/image-2.png b/typescript/onebite/yujin/image-2.png new file mode 100644 index 0000000..861c5bc Binary files /dev/null and b/typescript/onebite/yujin/image-2.png differ diff --git a/typescript/onebite/yujin/image-3.png b/typescript/onebite/yujin/image-3.png new file mode 100644 index 0000000..7fbb540 Binary files /dev/null and b/typescript/onebite/yujin/image-3.png differ diff --git a/typescript/onebite/yujin/image-4.png b/typescript/onebite/yujin/image-4.png new file mode 100644 index 0000000..94c2b19 Binary files /dev/null and b/typescript/onebite/yujin/image-4.png differ diff --git a/typescript/onebite/yujin/image-5.png b/typescript/onebite/yujin/image-5.png new file mode 100644 index 0000000..a45cf1e Binary files /dev/null and b/typescript/onebite/yujin/image-5.png differ diff --git a/typescript/onebite/yujin/image-6.png b/typescript/onebite/yujin/image-6.png new file mode 100644 index 0000000..f8bc5c5 Binary files /dev/null and b/typescript/onebite/yujin/image-6.png differ diff --git a/typescript/onebite/yujin/image.png b/typescript/onebite/yujin/image.png new file mode 100644 index 0000000..a97d4dc Binary files /dev/null and b/typescript/onebite/yujin/image.png differ