From 24d9cd8995d8a1bb0ee3d60e8cd1d4ded240df1b Mon Sep 17 00:00:00 2001 From: 1ilsang <1ilsang@naver.com> Date: Fri, 8 Dec 2023 22:18:23 +0900 Subject: [PATCH] docs: Add woowa-type --- apps/blog/_posts/book/woowa-type.md | 171 ++++++++++++++++++ .../src/features/styles/markdown/index.scss | 7 +- 2 files changed, 175 insertions(+), 3 deletions(-) create mode 100644 apps/blog/_posts/book/woowa-type.md diff --git a/apps/blog/_posts/book/woowa-type.md b/apps/blog/_posts/book/woowa-type.md new file mode 100644 index 00000000..ea348f22 --- /dev/null +++ b/apps/blog/_posts/book/woowa-type.md @@ -0,0 +1,171 @@ +--- +title: '우아한 타입스크립트 with 리액트 리뷰' +description: '주니어 FE를 위한 온보딩 책' +tags: ['book', 'review', 'typescript', 'react'] +coverImage: 'https://github.com/1ilsang/dev/assets/23524849/3e0ae612-003f-43e9-a6b0-d481697fc280' +date: '2023-11-24T12:37:42.554Z' +ogImage: + url: 'https://github.com/1ilsang/dev/assets/23524849/3e0ae612-003f-43e9-a6b0-d481697fc280' +--- + +cover + +"우아한 타입스크립트 with 리액트"의 리뷰를 해보려고 한다. + +## 선택하게 된 계기 + +두 가지 캐치프라이즈가 나를 이끌었다고 생각한다. + +1. 배달의민족 개발 사례로 살펴보는 +2. 주니어 개발자를 위한 온보딩 가이드 + +기술 스택이 동일하다 하여도 회사별로 사용 방식이 상당히 상이하다고 느낄 때가 많았기 때문에 이렇게 간접적으로나마 문화나 기술 적용 방식을 체험해 볼 수 있는 서적을 선호한다. + +또한 주니어 개발자를 위한 온보딩 가이드를 내걸었으므로 어떻게 신입이 회사의 일원으로 빠르게 흡수될 수 있을지 고민한 흔적이 있을 것이라 기대해 선택하게 되었다. + +## 간단한 요약 + +이 책은 앞에서 타입스크립트를 다루고 뒷부분은 리액트를 활용한 여러 기법이나 패턴에 관해 설명한다. + +앞쪽 타입은 신입이 보기에 조금 어려운 타입 좁히기까지 잘 다루고 있다. `extends`와 `infer`를 통한 타입 추론이 익숙하지 않다면 읽어보기를 추천하고 싶다. + +물론 타입스크립트나 리액트를 깊이 있게 공부하려고 이 책을 선택한다면 조금 부족할 수 있다고 생각한다(애초에 주니어 온보딩 책이다). + +온보딩 책인 만큼 API, 리렌더링, 훅스, State 등을 다양한 예제와 패턴을 통해 소개하는데 내용이 좋으므로 사수가 없는 환경에서 개발하는 분들이라면 읽기를 추천하고 싶다. + +## 인상깊었던 부분 + +책을 읽으면서 좋았던 예제나 포인트들을 가볍게 소개하고자 한다. + +### 타 언어의 타입 시스템과 비교 + +2장에서 타 언어의 타입 시스템을 거론하며 타입스크립트의 타입 철학을 엿볼 수 있게 해준다. 나는 이 부분이 좋았다. + +- 타입스크립트는 다른 명목적으로 구체화한 타입 시스템(Java, C++)과 다르게 구조로 타입을 구분한다. +- 타입스크립트는 타입 시스템을 집합으로 이해하면 된다. 타입은 값의 집합으로 생각할 수 있다. + +```tsx +class Person { + name: string; + constructor(name: string) { + this.name = name; + } +} +class Developer { + name: string; + age: number; + constructor(name: string, age: number) { + this.name = name; + this.age = age; + } +} +function greet(p: Person) { + console.log(p.name); +} +const developer = new Developer('zig', 20); + +// Person 타입을 받지만 Developer 타입 값을 넣어도 무관하다. +// 구조적 서브 타입이기 때문에 에러를 발생시키지 않는다. +// 서로 다른 두 타입 간의 호환성은 오직 타입 내부의 구조에 의해 결정된다. +greet(developer); // OK +``` + +- 타입스크립트가 위와 같은 구조적 타이핑을 채택한 이유는 자바스크립트를 모델링한 언어이기 때문이다. +- 자바스크립트는 덕 타이핑(duck typing)을 기반으로 만들어졌다. 덕타입은 매개변수가 올바르게 주어진다면 그 값이 어떻게 만들어졌는지 신경 쓰지 않고 허용한다. + +### 타입에 대한 고찰 + +```ts +type IdType = string | number; +type Numeric = number | boolean; +// 교차 타입은 두 타입을 모두 만족하는 경우에만 유지된다. +type Universal = IdType & Numeric; // number + +// 따라서 두 타입을 만족하지 못하는 경우 never가 된다. +type DeliveryTip = { + tip: number; +} +type Filter = { + tip: string; +} & DeliveryTip; +const filter: Filter = { tip: ... } // Type '...' is not assignable to type 'never'. +``` + +타입스크립트의 특징(집합적 특징과 구조적 타이핑 등)은 교차 타입에서 혼란을 야기할 수 있다. 이 부분에 대한 내용을 명확하게 설명하고 있다. + +### 개발팀과의 인터뷰 + +![woowa-story](https://github.com/1ilsang/dev/assets/23524849/7e43ccaf-306d-48f0-b0aa-48151564e8ee) + +중간중간 배민 개발팀들이 참조 출연해 해당 타입/기술을 쓰는지, 어떻게 생각하는지 인터뷰하는 것들이 있는데 실무에서 어떻게 생각하는지 생생하게 볼 수 있어서 흥미로웠다. + +자연스럽게 나 또한 질문에 대한 답을 해보곤 하면서 더 몰입할 수 있었다. + +### 친절한 설명 + +```ts +type CreateMutable = { + -readonly [Property in keyof Type]-?: Type[Property]; // - 는 오타가 아니다. +}; + +// 우아한 타입스크립트 https://www.youtube.com/whatch?v=ViS8DLd6o-E +// 제너릭 T 타입이 K로 추론되는 Promise라면 K를 반환하고 아니라면 any를 반환한다. +// 이를 통해 Promise 반환 타입을 좁혀서 추론할 수 있다. +type UnpackPromise = T extends Promise[] ? K : any; +``` + +타입스크립트의 문법 중에는 처음에 이해하기 어려운 것들이 있는데, 하나하나 과정을 풀어서 설명해 준다. + +### 실용적인 예제 + +특정 개념을 설명하고 활용하는 방법을 실무 코드를 기준으로 알려주기 때문에 상당히 실용적인 예제들로 채워져있다. + +```ts +const BottomSheetMap = { + RECENT_CONTACTS: RecentContactsBottomSheet, + CARD_SELECT: CardSelectBottomSheet, +}; +type BOTTOM_SHEET_ID = keyof typeof BottomSheetMap; +type BottomSheetStore = { + // BOTTOM_SHEET_ID(BottomSheetMap 객체의 key 값)의 property 값을 변환한다. + [index in BOTTOM_SHEET_ID as `${index}_BOTTOM_SHEET_ID`]: { + // ... + }; +}; +const store: BottomSheetStore = { + RECENT_CONTACTS_BOTTOM_SHEET_ID: { ... }, // key 값이 index로 가져온 값으로 변환된다. + CARD_SELECT_BOTTOM_SHEET_ID: { ... }, +}; +``` + +바텀 시트별 스토어를 선언하면서 키값을 특정하게 강제하고 있다. + +```ts +type ProductPrice = 100 | 200 | 300; +const getProductName = (productPrice: ProductPrice): string => { + if (productPrice === 100) return '배민 상품권 100원'; + if (productPrice === 200) return '배민 상품권 200원'; + else { + // exhaustiveCheck를 안 해주면 300원에 대한 코드가 없어도 에러가 발생하지 않음. + // 조건별 완벽한 타입 검증을 위해 사용하는 패턴 + exhaustiveCheck(productPrice); // Argument of type 'number' is not assignable to parameter of type 'never'. + return '배민 상품권'; + } +}; +// param 값이 never 타입이므로 해당 함수가 호출되기 전에 타입 가드가 다 되어 있어야 한다. +const exhaustiveCheck = (param: never) => { + throw new Error(`type error!`); +}; +``` + +Exhaustiveness Checking 패턴을 통해 이후 타입이 추가되어도 무결성을 지킬 수 있게 된다. + +이 외에도 컴파일 과정에 대한 설명이나 Axios 가이드 및 훅에서 유의할 점 등 여러 꿀팁들이 있다. + +## 맺으며 + +배민의 공유 문화는 본받을만하다고 생각한다. + +기술업계 특성상 비판적인 시선이 기본적으로 있기 때문에 외부 공개를 꺼릴 수도 있었겠지만, 기술에 대한 공유를 두려워하지 않고 책으로 펴낸 것에 리스펙하게 된다. + +여러 예제가 실제 코딩에 도움이 되기 때문에 추천하고 싶은 책이다. diff --git a/apps/blog/src/features/styles/markdown/index.scss b/apps/blog/src/features/styles/markdown/index.scss index 5e7f3e09..02f65b40 100644 --- a/apps/blog/src/features/styles/markdown/index.scss +++ b/apps/blog/src/features/styles/markdown/index.scss @@ -68,7 +68,6 @@ background-origin: content-box; line-height: 1.7em; border-left: 8px solid rgb(165 204 160); - border-radius: 4px; overflow: auto; margin-top: 1vh; margin-bottom: 1vh; @@ -81,7 +80,6 @@ } code { - border-radius: 4px; padding: 3px 4px; background-color: #19263a; border: 1px solid $base-color; @@ -93,7 +91,6 @@ h2, h3, h4 { - border-bottom: 1px solid hsl(210deg 18% 87% / 100%); font-weight: 600; padding-bottom: 0.1rem; padding-top: 1.5rem; @@ -119,10 +116,14 @@ h1 { @apply text-2xl mt-16 leading-snug; + + border-bottom: 1px solid hsl(210deg 18% 87% / 100%); } h2 { @apply text-3xl mt-12 leading-snug; + + border-bottom: 1px solid hsl(210deg 18% 87% / 100%); } h3 {