-
Notifications
You must be signed in to change notification settings - Fork 14
[1주차/오스카] 워크북 제출합니다. #7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1 +1,2 @@ | ||
| .idea/ | ||
| .idea/ | ||
| .pnpm-store/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| <!doctype html> | ||
| <html lang="ko"> | ||
| <head> | ||
| <meta charset="UTF-8" /> | ||
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
| <title>나의 웹 개발 카드</title> | ||
| <link rel="stylesheet" href="style.css" /> | ||
| <script src="script.js" defer></script> | ||
| </head> | ||
| <body> | ||
| <main class="card"> | ||
| <header> | ||
| <p>WEEK 0</p> | ||
| <p id="message">HTML, CSS, JavaScript를 배우고 있습니다.</p> | ||
| </header> | ||
|
|
||
| <section> | ||
| <h2>배우고 싶은 기술</h2> | ||
| <ul class="skills"> | ||
| <li class="skill">HTML</li> | ||
| <li class="skill">CSS</li> | ||
| <li class="skill">JavaScript</li> | ||
| </ul> | ||
| </section> | ||
|
|
||
| <button id="cheer-button" type="button">응원 메시지 보기</button> | ||
| </main> | ||
| </body> | ||
| </html> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| const message = document.querySelector("#message"); | ||
| const cheerButton = document.querySelector("#cheer-button"); | ||
|
|
||
| cheerButton.addEventListener("click", function () { | ||
| message.textContent = "좋아요! 작은 코드부터 직접 바꾸어 봅시다. 🚀"; | ||
| }); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| const student = { | ||
| name: "광수", | ||
| skills: ["HTML", "CSS", "JavaScript"], | ||
| }; | ||
|
|
||
| function printSkills(skills) { | ||
| for (const skill of skills) { | ||
| if (skill === "JavaScript") { | ||
| console.log(`${skill}: 화면에 동작을 더합니다.`); | ||
| } else { | ||
| console.log(skill); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| console.log(student.name); | ||
| printSkills(student.skills); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| body { | ||
| margin: 0; | ||
| background: #f1f5f9; | ||
| color: #0f172a; | ||
| } | ||
|
|
||
| .card { | ||
| box-sizing: border-box; | ||
| width: 90%; | ||
| max-width: 520px; | ||
| margin: 40px auto; | ||
| padding: 32px; | ||
| border: 1px solid #dbeafe; | ||
| border-radius: 20px; | ||
| background: #ffffff; | ||
| } | ||
|
|
||
| .skills { | ||
| display: flex; | ||
| flex-wrap: wrap; | ||
| gap: 8px; | ||
| padding: 0; | ||
| list-style: none; | ||
| } | ||
|
|
||
| .skill { | ||
| padding: 6px 10px; | ||
| border-radius: 16px; | ||
| background: #dbeafe; | ||
| } | ||
|
|
||
| button { | ||
| margin-top: 16px; | ||
| padding: 10px 16px; | ||
| border: 0; | ||
| border-radius: 10px; | ||
| background: #2563eb; | ||
| color: #ffffff; | ||
| } | ||
|
|
||
| button:hover { | ||
| background: #1d4ed8; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,114 @@ | ||
| // 2. 컴파일 타임과 런타임 | ||
| { | ||
| function introduceStudent(studentName: string, currentLevel: number) { | ||
| return studentName + " 님은 현재 " + currentLevel + "레벨이에요."; | ||
| } | ||
|
|
||
| // introduceStudent("광수", "1"); // string을 number 자리에 전달하면 컴파일 오류 | ||
| console.log(introduceStudent("광수", 1)); | ||
| // const names = ["광수"]; | ||
| // console.log(names[5].toUpperCase()); // 기본 설정에서는 런타임 오류가 날 수 있음 | ||
| } | ||
|
|
||
| // 3. 값의 종류와 타입 추론 | ||
| { | ||
| let studentName = "광수"; // string | ||
| let currentWeek = 1; // number | ||
| let isCompleted = false; // boolean | ||
| const monthlySkills: string[] = ["HTML", "CSS", "TypeScript"]; | ||
| // monthlySkills.push(123); // number는 string[]에 넣을 수 없음 | ||
|
|
||
| const firstMember = { name: "광수" }; | ||
| const secondMember = { name: "광수" }; | ||
| console.log(studentName, currentWeek, isCompleted, monthlySkills); | ||
| console.log(firstMember === secondMember); // false | ||
| } | ||
|
|
||
| // 4. 객체와 함수 타입 | ||
| { | ||
| type StudyMember = { name: string; level: number; isLeader: boolean }; | ||
| const member: StudyMember = { name: "광수", level: 1, isLeader: false }; | ||
|
|
||
| function createMemberCard(studyMember: StudyMember) { | ||
| return studyMember.name + " 님, " + studyMember.level + "레벨"; | ||
| } | ||
|
|
||
| console.log(createMemberCard(member)); // 반환 타입은 string으로 추론 | ||
| } | ||
|
|
||
| // 5. 리터럴 유니언 타입 | ||
| { | ||
| type MemberRole = "leader" | "member"; | ||
|
|
||
| function getRoleMessage(role: MemberRole) { | ||
| if (role === "leader") return "스터디를 이끌어요."; | ||
| return "스터디에 참여해요."; | ||
| } | ||
|
|
||
| console.log(getRoleMessage("leader")); | ||
| console.log(getRoleMessage("member")); | ||
| // getRoleMessage("manager"); // 허용하지 않은 역할이라 컴파일 오류 | ||
| } | ||
|
|
||
| // 6. null, undefined, 옵셔널 체이닝과 널 병합 | ||
| { | ||
| type StudyMember = { name: string; githubId?: string }; | ||
| const members: StudyMember[] = [ | ||
| { name: "광수", githubId: "gwangsoo" }, | ||
| { name: "지수" }, | ||
| ]; | ||
| let selectedMember: StudyMember | null = null; | ||
| const foundMember = members.find((member) => member.name === "현우"); | ||
| console.log(selectedMember); // null | ||
| console.log(foundMember); // undefined | ||
|
|
||
| if (foundMember) console.log(foundMember.name); | ||
| else console.log("회원을 찾지 못했어요."); | ||
|
|
||
| const studyHour: number | undefined = 0; | ||
| console.log(studyHour || 1); // 1 | ||
| console.log(studyHour ?? 1); // 0 | ||
| console.log(foundMember?.githubId ?? "등록되지 않음"); | ||
| } | ||
|
|
||
| // 7. unknown 값 좁히기 | ||
| { | ||
| function formatStudyWeek(week: unknown) { | ||
| if (typeof week === "number") return "현재 " + week + "주차예요."; | ||
| if (typeof week === "string") return "입력한 주차: " + week; | ||
| return "주차를 확인할 수 없어요."; | ||
| } | ||
|
|
||
| console.log(formatStudyWeek(1)); | ||
| console.log(formatStudyWeek("첫째")); | ||
| console.log(formatStudyWeek(null)); | ||
| } | ||
|
|
||
| // 8. 제네릭으로 입력과 결과의 타입 관계 지키기 | ||
| { | ||
| function createBox<T>(value: T) { | ||
| return { value }; | ||
| } | ||
|
|
||
| const nameBox = createBox("광수"); // value: string | ||
| const scoreBox = createBox(100); // value: number | ||
| const memberBox = createBox({ name: "광수", level: 1 }); | ||
| console.log(nameBox.value, scoreBox.value, memberBox.value); | ||
| } | ||
|
|
||
| // 9. strict 모드에서 타입 오류 해결하기 | ||
| { | ||
| type WeeklyGoal = { title: string; targetCount: number }; | ||
| const weeklyGoal: WeeklyGoal = { | ||
| title: "TypeScript 예제 연습", | ||
| targetCount: 3, | ||
| }; | ||
|
|
||
| function printGoal(goal: WeeklyGoal): string { | ||
| const message = goal.title + ": " + goal.targetCount + "개"; | ||
| console.log(message); | ||
| return message; | ||
| } | ||
|
|
||
| printGoal(weeklyGoal); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,123 @@ | ||
| - PK, FK란? | ||
| - **PK (기본키):** 테이블 내의 각 레코드를 고유하게 식별하는 컬럼. | ||
| - **조건:** `UNIQUE` (중복 불가) + `NOT NULL` (비어있을 수 없음). | ||
| - **개발자 Point:** 대부분의 RDBMS에서 PK를 지정하면 해당 컬럼 기준으로 클러스터링 인덱스(물리적 데이터 정렬)가 자동 생성되어 조회 성능의 기준점이 됩니다. | ||
| - **FK (외래키):** 다른 테이블의 PK(또는 Unique 키)를 참조하는 컬럼. | ||
| - **목적:** 데이터의 **참조 무결성**을 보장합니다. (예: 존재하지 않는 유저의 주문 데이터가 생기는 것을 막음) | ||
| - **개발자 Point:** 실무에서는 성능 저하(Insert/Update 시 검증 오버헤드)나 데드락 이슈 때문에 DB 단의 물리적인 FK 제약조건을 걸지 않고, **애플리케이션(코드) 레벨에서 논리적 연관관계만 통제**하는 경우도 매우 많습니다. | ||
|
Comment on lines
+5
to
+7
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win 애플리케이션 검사를 FK 제약조건과 동등하게 설명하지 말아 주세요. 애플리케이션 레벨 검사만 사용하면 동시 요청이나 직접 실행한 SQL을 통해 고아 레코드가 생길 수 있습니다. FK를 생략하는 선택은 가능하지만, 모든 쓰기 경로와 트랜잭션 처리에서 무결성을 보장해야 한다는 조건을 함께 설명해 주세요. 경로 지침의 기술적 정확성 기준에 따른 지적입니다. 🤖 Prompt for AI AgentsSource: Path instructions |
||
| - ERD란? | ||
|
|
||
| 데이터베이스의 구조(엔티티, 속성, 관계)를 한눈에 파악할 수 있게 그린 도면입니다. | ||
|
|
||
| - **목적:** 기획자, 개발자, DBA 간의 원활한 구조적 커뮤니케이션 및 설계 문서화. | ||
| - **구성:** 엔티티(테이블), 어트리뷰트(컬럼), 릴레이션십(선으로 연결된 관계와 카디널리티 표현 - 1:N 등). | ||
| - 연관관계란? 그리고 연관관계를 설정하는 방법은? | ||
|
|
||
| 테이블 간 데이터가 서로 어떻게 연결되는지를 의미합니다. | ||
|
|
||
| - **1:1 (일대일):** 양쪽 테이블이 서로 하나의 레코드만 가짐. (예: `User` - `UserProfile`) | ||
| - **1:N (일대다):** 한 쪽 레코드가 다른 쪽 레코드 여러 개를 가짐. 실무에서 가장 흔합니다. (예: `User` 1명 - `Order` N개) | ||
| - **N:M (다대다):** 양쪽 모두 여러 개를 가짐. (예: `Student` - `Class`) | ||
|
|
||
| **[연관관계 설정(해결) 방법]** | ||
|
|
||
| 1. **1:N의 경우:** 항상 **'다(N)' 쪽 테이블에 FK를 배치**합니다. (`Order` 테이블에 `user_id` 컬럼 추가) | ||
| 2. **N:M의 경우:** RDBMS는 다대다 관계를 직접 표현할 수 없습니다. 따라서 중간에 매핑 테이블(연결 테이블)을 만들어 **1:N 관계로 두 번 풀어냅니다**. (예: `Student_Class_Mapping` 테이블을 만들고 양쪽의 PK를 FK로 가짐) | ||
|
|
||
| ## | ||
|
|
||
| - 정규화란? | ||
|
|
||
| 데이터의 **중복을 최소화**하고, 삽입/수정/삭제 시 발생하는 이상 현상(Anomaly)을 방지하기 위해 테이블을 쪼개는 설계 과정입니다. | ||
|
|
||
| - **1정규형(1NF):** 모든 컬럼은 원자값(하나의 값)만 가져야 한다. (배열 불가) | ||
| - **2정규형(2NF):** (복합키인 경우) 부분 함수 종속을 제거한다. 즉, PK 일부에만 종속된 컬럼을 분리. | ||
| - **3정규형(3NF):** 이행적 함수 종속을 제거한다. (A->B, B->C일 때 C가 A에 종속되는 현상 분리) | ||
| - **개발자 Point:** 무조건 정규화가 답은 아닙니다. 쪼갤수록 데이터 무결성은 높아지지만, 데이터를 가져올 때 `JOIN`이 많아져 읽기 성능이 떨어질 수 있습니다. | ||
| - 반 정규화란? | ||
|
|
||
| **읽기(SELECT) 성능 향상**을 위해 정규화 원칙을 의도적으로 위배하고 데이터를 중복시키거나 합치는 기법입니다. | ||
|
|
||
| - **방법 예시:** | ||
| - 조인이 잦은 두 테이블 병합 | ||
| - 자주 조회되는 타 테이블의 컬럼을 중복으로 복사해 두기 | ||
| - 집계 컬럼(총 주문 금액 등)을 미리 계산해서 저장해 두기 | ||
| - **개발자 Point:** 읽기 속도는 빨라지지만, 데이터 수정(Update) 시 중복된 데이터를 모두 변경해야 하므로 정합성(Consistency)이 깨질 위험이 큽니다. "조회 성능이 극도로 중요할 때" 최후의 수단으로 씁니다. | ||
|
|
||
| ## | ||
|
|
||
| - DB에서의 상속 관계 표현은 어떻게 하는가? | ||
|
|
||
| 객체 지향 언어에는 상속이 있지만, RDBMS에는 상속 개념이 없습니다. 이를 물리적 테이블로 구현하는 방식은 3가지가 있습니다. (ORM/JPA를 쓴다면 매핑 전략과 동일합니다.) | ||
|
|
||
| 1. **조인 테이블 (Joined Strategy):** | ||
| - 부모, 자식 테이블을 각각 만들고 조인으로 데이터를 엮음. (정규화된 방식) | ||
| - *장단점:* 저장 공간 효율이 좋고 구조가 깔끔하지만, 조회 시 JOIN이 많이 발생합니다. | ||
| 2. **단일 테이블 (Single Table Strategy):** | ||
| - 모든 자식 속성을 통짜 부모 테이블 1개에 다 때려 넣고, `DTYPE`(구분자) 컬럼으로 타입을 구분. | ||
| - *장단점:* JOIN이 필요 없어 성능이 가장 빠르지만, 자신이 안 쓰는 속성은 모두 `NULL`이 허용되어야 하는 단점이 있습니다. | ||
|
Comment on lines
+51
to
+58
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 상속 매핑 전략의 설명을 조건부로 수정해 주세요. 관계형 모델에 객체지향 상속이 일반적으로 없다는 설명은 적절하지만, 일부 DBMS는 별도의 테이블 상속 기능을 제공합니다. 또한 단일 테이블 전략이 항상 가장 빠른 것은 아닙니다. 행 폭, 경로 지침의 기술적 정확성 기준에 따른 지적입니다. 🤖 Prompt for AI AgentsSource: Path instructions |
||
| 3. **구현 클래스마다 테이블 (Table per Concrete Class):** | ||
| - 부모 테이블 없이 자식 테이블만 각각 만듦. | ||
| - *장단점:* 실무에서 거의 안 씁니다. (부모 타입으로 묶어서 전체 조회하거나 다형성을 다루기 매우 힘듦) | ||
| - 인덱스란? | ||
|
|
||
| 책의 '맨 뒤 색인(목차)'과 같습니다. 데이터를 **빠르게 찾기(SELECT) 위해** B-Tree 등의 자료구조로 정렬해 놓은 별도의 메모리/디스크 공간입니다. | ||
|
|
||
| - **동작 원리:** 인덱스가 없으면 DB는 테이블 전체를 뒤집니다(Full Table Scan). 인덱스가 있으면 트리 구조를 타고 O(log N)의 속도로 데이터를 찾아냅니다. | ||
| - **종류:** | ||
| - **Clustered Index:** 테이블당 1개. 데이터 자체가 인덱스 순서대로 물리적으로 정렬됨. (주로 PK) | ||
| - **Non-Clustered Index:** 여러 개 생성 가능. 데이터 위치를 가리키는 포인터만 가짐. (일반적인 인덱스) | ||
| - **개발자 관점의 핵심 주의사항:** | ||
| - **Trade-off:** 조회 속도는 비약적으로 오르지만, `INSERT`, `UPDATE`, `DELETE` 시에는 인덱스 트리도 재정렬해야 하므로 쓰기 성능은 떨어지고 저장 공간을 추가로 차지합니다. | ||
| - **카디널리티 (Cardinality):** 중복도가 낮고 고유한 값이 많은 컬럼(예: 주민번호, 이메일)에 인덱스를 걸어야 효과가 좋습니다. (성별처럼 남/녀 두 값뿐인 컬럼은 인덱스 효과가 거의 없습니다.) | ||
| - **복합 인덱스:** 두 개 이상의 컬럼을 묶어 인덱스를 만들 때, **컬럼의 순서**가 성능을 좌우합니다. (조회 조건에 무조건 포함되는 컬럼, 카디널리티가 높은 컬럼을 앞쪽에 배치해야 함) | ||
|
Comment on lines
+72
to
+73
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 복합 인덱스의 열 순서 규칙을 수정해 주세요. 카디널리티가 높은 컬럼을 항상 앞에 둔다는 규칙은 보편적이지 않습니다. 실제 조건의 동등 비교·범위 비교·정렬 여부와 B-Tree의 왼쪽부터 적용되는 규칙을 함께 고려해야 합니다. 경로 지침의 기술적 정확성과 심화 학습 추천 기준에 따른 지적입니다. 🤖 Prompt for AI AgentsSource: Path instructions |
||
|
|
||
|
|
||
| - TypeScript와 정적 타입 검사 | ||
| - JavaScript와 비교했을 때 TypeScript는 오류를 언제, 어떤 방식으로 확인하나요? | ||
|
|
||
| 코드를 실행하기 전(컴파일 타임)에, 코드의 문맥과 타입을 정적 분석하여 에디터에서 즉시 확인합니다. | ||
|
|
||
| - 컴파일 타임 오류와 런타임 오류는 어떤 차이가 있나요? | ||
| - **컴파일 타임 오류:** 개발자가 코드를 짜는 중에 발견되어 배포(실행)를 막아주는 안전한 오류입니다. | ||
| - **런타임 오류:** 프로그램이 실제 실행되는 도중에 발생하여 서비스(앱)를 중단(Crash)시키는 위험한 오류입니다. | ||
| - TypeScript의 타입 정보가 실행되는 JavaScript에 남지 않는 이유는 무엇일까요? | ||
|
|
||
| 브라우저나 Node.js 엔진은 TypeScript 문법을 이해하지 못하기 때문에, 호환성 유지와 런타임 성능 저하(오버헤드)를 막기 위해 컴파일 과정에서 타입 정보를 모두 지워버리기(Type Erasure) 때문입니다. | ||
|
Comment on lines
+79
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win TypeScript의 컴파일 타임과 런타임 경계를 정확히 설명해 주세요. TypeScript 오류가 항상 실행이나 배포를 막는 것은 아닙니다. 경로 지침의 기술적 정확성 기준에 따른 지적입니다. 🤖 Prompt for AI AgentsSource: Path instructions |
||
|
|
||
| - 타입 추론과 타입 모델링 | ||
| - TypeScript가 타입을 추론하도록 두는 경우와 타입을 직접 작성하는 경우는 각각 언제 알맞을까요? | ||
| - **추론:** `let age = 30;`처럼 선언과 동시에 초기화되어 타입이 명확할 때 알맞습니다. | ||
| - **직접 작성:** 함수의 매개변수/반환값, API 응답 객체처럼 규격과 형태를 엄격하게 강제해야 할 때 알맞습니다. | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win 외부 API 응답의 타입 선언과 런타임 검증을 구분해 주세요. API 응답에 타입을 선언해도 실제 데이터의 형태를 검증하지는 않습니다. 외부 데이터는 경로 지침의 핵심 개념 보완 기준에 따른 지적입니다. Also applies to: 119-120 🤖 Prompt for AI AgentsSource: Path instructions |
||
| - 객체와 함수의 형태를 타입으로 표현하면 어떤 실수를 미리 찾을 수 있을까요? | ||
|
|
||
| 존재하지 않는 프로퍼티 접근(오타), 잘못된 타입의 값 할당, 필수 매개변수 누락 등의 실수를 코드 작성 즉시 발견할 수 있습니다. | ||
|
|
||
| - `type`과 `interface`는 표현 범위와 확장 방식에서 어떤 차이가 있을까요? | ||
| - **표현 범위:** `type`은 원시값, 유니언, 튜플 등 모든 타입을 표현할 수 있지만, `interface`는 객체의 형태만 표현 가능합니다. | ||
| - **확장 방식:** `type`은 `&`(인터섹션)로 교차시켜야 하지만, `interface`는 `extends` 키워드나 선언 병합(동일한 이름으로 중복 선언 시 자동 병합)을 통해 객체 지향적으로 쉽게 확장할 수 있습니다. | ||
| - 유니언 타입과 타입 좁히기 | ||
| - 여러 타입 중 하나가 될 수 있는 값을 유니언 타입으로 표현하면 어떤 장점이 있나요? | ||
|
|
||
| 타입 검사를 포기하는 `any`를 쓰지 않고도, 지정된 타입 후보군(`A | B`) 안에서만 동작하도록 제한하여 유연성과 타입 안전성을 동시에 챙길 수 있습니다. | ||
|
|
||
| - 조건문, `typeof`와 판별 프로퍼티는 타입을 어떻게 좁히나요? | ||
|
|
||
| `if(typeof a === 'string')`처럼 타입 가드를 거치거나 객체가 가진 고유한 리터럴 값(판별 프로퍼티)을 비교하면, TypeScript가 해당 조건문 블록 안에서는 변수의 타입을 구체적인 하나로 확정(Narrowing)해 줍니다. | ||
|
|
||
| - `null`과 `undefined`가 포함된 값을 안전하게 다룰 때 옵셔널 체이닝과 널 병합 연산자는 어떤 역할을 하나요? | ||
| - **옵셔널 체이닝(`?.`):** 객체가 nullish할 때 크래시를 내는 대신 안전하게 `undefined`를 반환합니다. | ||
| - **널 병합 연산자(`??`):** 값이 nullish할 때 설정해둔 안전한 기본값을 대신 반환해 줍니다. | ||
|
|
||
|
|
||
|
|
||
| - 타입 안전성과 제네릭 | ||
| - `any`와 `unknown`은 타입 검사를 허용하는 방식이 어떻게 다른가요? | ||
| - **`any`:** 타입 검사기를 아예 꺼버리고 모든 프로퍼티 접근과 조작을 무조건 허용합니다. | ||
| - **`unknown`:** 모든 값을 넣을 수는 있지만, 사용할 때는 반드시 타입 검사(타입 좁히기)를 거쳐서 타입을 증명해야만 조작을 허용합니다. | ||
| - 여러 타입을 받을 때 `unknown`과 제네릭은 각각 어떤 상황에 알맞을까요? | ||
| - **`unknown`:** 외부 API 응답처럼 들어올 데이터의 타입을 짐작조차 할 수 없을 때 알맞습니다. | ||
| - **제네릭:** 함수나 클래스가 다양한 타입을 받아서 동작하되, 입력받은 타입의 규칙을 반환값까지 그대로 유지하고 싶을 때 알맞습니다. | ||
| - 제네릭은 입력 타입과 출력 타입의 관계를 어떻게 유지하나요? | ||
|
|
||
| `<T>`와 같은 '타입 변수'를 선언하여, 함수 호출 시점에 전달된 입력 타입을 `T`에 캡처한 뒤, 그 `T`를 반환 타입으로 그대로 사용함으로써 입력과 출력 간의 연결 고리를 유지합니다. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| node_modules/ | ||
| dist/ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| # 1주차 TypeScript 미션 기록 | ||
|
|
||
| <details> | ||
| <summary>필수 미션</summary> | ||
|
|
||
| 회원 ID, 이름, 역할, 선택적 GitHub 아이디를 타입으로 정의하고 서로 다른 회원 두 명을 작성했습니다. [전체 코드](src/index.ts) | ||
|
|
||
| ```ts | ||
| type MemberRole = "leader" | "member"; | ||
|
|
||
| interface StudyMember { | ||
| id: number; | ||
| name: string; | ||
| role: MemberRole; | ||
| githubId?: string; | ||
| } | ||
|
|
||
| const members: StudyMember[] = [ | ||
| { id: 1, name: "광수", role: "leader", githubId: "gwangsoo" }, | ||
| { id: 2, name: "지수", role: "member" }, | ||
| ]; | ||
|
|
||
| function createMemberMessage(memberId: number): string { | ||
| const member = members.find((item) => item.id === memberId); | ||
| if (!member) return `ID ${memberId}에 해당하는 회원이 없습니다.`; | ||
|
|
||
| const roleMessage = member.role === "leader" ? "리더" : "멤버"; | ||
| const githubId = member.githubId ?? "등록되지 않음"; | ||
| return `${member.name} 님은 ${roleMessage}입니다. GitHub: ${githubId}`; | ||
| } | ||
| ``` | ||
|
|
||
| `pnpm exec tsc --noEmit` 타입 검사, `pnpm exec tsc` 컴파일, `node dist/index.js` 실행이 모두 성공했습니다. 실행 결과: | ||
|
|
||
| ```text | ||
| 광수 님은 리더입니다. GitHub: gwangsoo | ||
| 지수 님은 멤버입니다. GitHub: 등록되지 않음 | ||
| ID 999에 해당하는 회원이 없습니다. | ||
| ``` | ||
|
|
||
| </details> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
PK와 클러스터링 인덱스의 관계를 DBMS 공통 규칙으로 쓰지 말아 주세요.
UNIQUE와NOT NULL설명은 정확합니다. 그러나 PK를 지정하면 클러스터링 인덱스가 자동으로 생성되고 데이터가 물리적으로 정렬된다는 내용은 DBMS마다 다릅니다. PK가 고유 인덱스를 만들 수는 있지만, 클러스터링 여부와 유지 방식은 엔진과 설정에 따라 달라집니다. PostgreSQL과 InnoDB의 차이를 예로 보완해 주세요.경로 지침의 기술적 정확성 기준에 따른 지적입니다.
Also applies to: 68-69
🤖 Prompt for AI Agents
Source: Path instructions