TypeScript에서 {}는 null/undefined를 제외한 모든 값을 뜻한다.

|

TypeScript에서 {}는 조금 애매한 타입인데,
null과 undefined를 제외한 모든 값을 뜻한다.

let a: {} = 123; // ✅ number 가능
let b: {} = 'hello'; // ✅ string 가능
let c: {} = { x: 1 }; // ✅ object 가능
let d: {} = []; // ✅ array 가능

let e: {} = null; // ❌ 오류
let f: {} = undefined; // ❌ 오류

BFE.dev문제에서 NonNullable<T>를 직접 구현하는 풀이가 있었는데,
정답은 아래와같았다.

type MyNonNullable<T> = T & {};

유니언 타입에서 & {}를 교차시키면,
null과 undefined만 걸러지고 나머지는 그대로 유지된다.

type Ex = string | null | undefined;

type Result = Ex & {};
// = (string & {}) | (null & {}) | (undefined & {})
// = string | never | never
// = string

즉 T가 유니언일 때, 각각을 {}와 교차시켜 계산하여 null/undefined를 걸러낸다.
(유니언은 반복문의 효과를 가져옴)

WIL - 2025.08 Week 4

|

이번 주는 회사에 출근하지 않고 재택으로 일했다. 개발팀장님이 출근할 때는 맞춰야 하지만, 크롤링 작업은 집에서 집중하는 것이 더 효율적이라고 판단했다.

크롤링 자동화를 위해 Electron, BrightData, Playwright로 개발을 시도했으나 실패했다. 시간 압박 속에서 조급하게 접근한 것이 원인이었던 것 같다. 다행히 동료의 코드로 수동 크롤링을 이어갈 수 있었다. 실패 과정에서 얻은 것도 있었다. 페이지 로딩 문제는 크롬 디버그 모드와 user-agent 설정으로 해결할 수 있다는 점을 알게 되었다. 다만 셀렉터 변동성이 많아 완전 자동화까지는 아직 어렵다고 느꼈다.

학습 측면에서는 패턴으로 익히고 설계로 완성하는 리액트를 읽기 시작했다. TDD의 레드-그린-리팩터 주기를 배우고, ACL(오류 방지 계층) 개념도 접했다. 회사에서 사용하던 services 구조가 바로 ACL의 일종임을 깨달았다. 데이터 변환을 한 곳에서만 처리해 뷰를 단순하게 유지한다는 점이 인상적이었다.

또, CS50 강의를 듣기 시작했다. 전구의 on/off를 1과 0으로 표현하는 이진수 개념을 배우고, 각 자리수가 2의 거듭제곱을 나타낸다는 것도 이해했다. 강의는 아직 초반이지만 강사의 열정 덕분에 흥미롭게 보고 있다.

추가로 BFE.dev에서 타입스크립트 문제를 하나씩 다시 풀고 있다.

한 주를 몰아 적다 보니 글이 길어지고 일기처럼 흘러간다. 하지만 지금은 배운 것을 기록하는 습관을 만드는 것이 더 중요하다고 생각한다. 언젠가는 짧고 단정한 기록으로 다듬어낼 수 있을 거라 믿는다.

WIL(Weekly I Learned)를 쓰게 되다.

|

하루는 금방 지나가고, 매일 무언가를 배우지만 금세 흘러가 버린다.
예전에 TIL을 썼을 땐 그 순간의 기록이 쌓이는 게 즐거웠다. 하지만 시간이 지나면서 어느새 숙제처럼 느껴지고, 결국 깃 잔디만 채우는 일로 변해버렸다. 기록의 의미가 흐려진 순간이었다.

요즘은 재택을 주로 하면서 출퇴근에 쓰던 시간을 아끼고 있다. 하지만 돌이켜보면 그 시간조차 온전히 잠으로만 흘려보내고 있었다. 편안하긴 했지만, 어딘가 아쉽다는 생각이 들었다.
그래서 다시 기록을 시작해 보기로 했다. 다만 이번에는 하루가 아니라 한 주 단위로.

억지로 모든 걸 남기려 하지 않을 거다. 그냥 내키는 대로 적고 싶은 만큼만 적을 거다. 살아보니 그게 나한테는 더 오래가는 방식이었다.

Weekly I Learned에서는 이번 주에 새로 알게 된 개념과 배운 내용, 회사에서의 업무 경험, 그리고 그 밖의 배움을 얻은 순간들을 함께 기록해둘 거다.
기록은 언젠가 되돌아보았을 때 내 발자취가 되어줄 거라 믿는다.

타입스크립트 분배 조건부 타입

|

BFE.dev 사이트의 타입스크립트 챌린지를 풀면서 새롭게 알게 된 개념들을 정리합니다.


TypeScript 조건부 타입에서 중요한 규칙 중 하나는
조건부 타입이 유니언 타입에 대해 자동으로 분배(distribute) 된다는 점이다.

📌 기본 형태

T extends U ? X : Y

여기서 T가 유니언 타입 (A | B | C)이라면,
조건부 타입은 각 멤버별로 나눠서 평가된다.

즉:

(A | B | C) extends U ? X : Y

는 다음처럼 분배된다.

(A extends U ? X : Y) |
(B extends U ? X : Y) |
(C extends U ? X : Y)

📌 분배를 막는 방법

분배가 항상 원하는 동작은 아닐것이다.
만약 T 전체가 E에 속하는지를 한 번에 체크하고 싶다면,
[T]처럼 튜플로 감싸주면 분배가 일어나지 않는다.

type NoDistribute<T, E> = [T] extends [E] ? never : T

✅ 정리

  • 조건부 타입에서 T가 유니언이면 멤버별로 분배된다. (반복문처럼 각 멤버를 순회하면서 조건을 적용한다)

  • 이를 분배 조건부 타입(Distributive Conditional Types) 이라고 한다.

  • 분배를 원하지 않을 때는 [T] extends [U]로 튜플 감싸기를 활용한다.

  • Exclude, Extract, NonNullable 등 여러 유틸리티 타입이 이 규칙을 기반으로 한다.

Cursor에서 Prettier Formatter 설정하기

|

매번 설정할 때마다 GPT한테 물어보는 게 귀찮아서, 이번에 아예 정리해두기로 했다.
Cursor(또는 VSCode 기반 에디터)에서 Prettier가 포맷터로 적용되지 않을 때 아래 순서대로 설정하면 된다.


✍️ 설정 방법

  1. Ctrl + Shift + P (Cmd + Shift + P on macOS) 누르기
    Preferences: Open Settings (UI) 입력 후 선택

  2. 상단 검색창에 default formatter 입력

  3. Editor: Default Formatter 항목 선택
    → 기본값이 None이라면, 드롭다운에서
    Prettier - Code formatter 또는 esbenp.prettier-vscode 선택


✅ 설정 완료 후

이제부터는 파일을 저장할 때 자동으로 Prettier 규칙에 맞게 포맷팅된다.
줄 정렬, 들여쓰기, 세미콜론 처리 등 깔끔하게 자동 적용된다.


💡 참고

추가로 아래 설정을 해두면 더 편리하다:

// .vscode/settings.json 또는 User Settings
{
  "editor.formatOnSave": true,
  "editor.defaultFormatter": "esbenp.prettier-vscode"
}