TypeScript 고급 타입 패턴 정리 — 제네릭, 유니온·인터섹션, 매핑, 조건부, 유틸리티

개요 TypeScript의 고급 타입은 단순 오류 방지 수준을 넘어 재사용성과 유지보수성을 끌어올리는 핵심 도구임 제네릭, 유니온·인터섹션, 매핑 타입, 조건부 타입, 그리고 실무에서 자주 쓰는 유틸리티 타입을 간단 예시와 함께 정리함 제네릭 타입을 값처럼 받아서 사용하는 패턴으로, 선언 시점이 아니라 사용 시점에 타입을 결정함 any 대비 타입 정보를 잃지 않으면서 다양한 타입을 수용 가능 기본 형태 사용 입력과 출력 타입의 관계를 보존하는 데 초점 function wrap(value: any) { return { value } } function wrapBox<T>(value: T) { return { value } } const stringBox = wrapBox("Hello") const numberBox = wrapBox(123) T는 관습적 이름이며 의미가 드러나는 이름 사용 권장 제네릭 제한이 필요한 경우 extends를 사용해 제약 가능 ex) 유니온과 인터섹션 여러 타입을 조합해 표현력을 높이는 방법 ...

January 25, 2026

RxJS 핵심 가이드와 내부 동작 이해 Observable Subject Teardown Scheduler Operator

개요 RxJS는 Reactive Extensions for JavaScript의 약자이며 비동기 데이터 흐름을 스트림 Observable로 다루는 라이브러리임 이벤트, API 응답, 클릭, WebSocket처럼 시간에 따라 변하는 값을 하나의 연속 흐름으로 모델링 가능 핵심 비교 Promise는 값 1개 처리 Observable은 값 0개부터 무한대까지 처리 Observable 핵심 정의 시간에 따라 변경되는 데이터를 push 기반 스트림으로 표현한 객체 구독 subscribe 시점에만 실행되는 lazy 특성 구독 해제 unsubscribe 시 리소스 정리 가능 특징 lazy 실행으로 불필요한 작업 방지 cancel 가능으로 누수 방지 0~무한개의 값 연속 처리 간단 예시 ...

January 24, 2026

TypeScript/ESM import 경로 정리: '@', '#', 상대 경로의 의미와 설정

개요 TypeScript와 ESM에서 자주 보이는 세 가지 import 패턴 import … from ‘@…’ import … from ‘…’ import … from ‘#…’ 표기만 비슷할 뿐, 해석 주체와 동작 범위가 다름 ‘@‘는 경로 별칭 또는 npm 스코프 패키지 의미 가능 ‘…‘는 상대·절대 경로로 파일 시스템 기준 해석 ‘#‘는 Node.js 패키지 imports 또는 브라우저 import maps에서의 별칭으로 사용 아래에서 각 패턴의 의미, 설정 지점, 주의사항을 정리함 ‘@…’ 경로의 두 가지 의미 1) 경로 별칭 path alias 의도: 길고 복잡한 상대 경로를 짧게 추상화 설정 지점: tsconfig.json 의 compilerOptions.paths와 baseUrl 예시 { "compilerOptions": { "baseUrl": "./", "paths": { "@models/*": ["src/models/*"], "@utils/*": ["src/utils/*"] } } }import { User } from '@models/User' import { calculate } from '@utils/math' 장점 상대 경로를 단순화, 가독성 및 리팩터링 내성 향상 주의 tsconfig paths는 타입 체크러와 에디터가 이해하는 별칭일 뿐, 런타임 해석자는 아님 Node.js 런타임은 tsconfig paths를 모름. 번들러 설정별 alias 또는 전용 로더를 함께 구성 필요 예: Vite, Webpack, ts-node, tsconfig-paths 등 도구별 설정 일치 필요 2) 스코프된 패키지 scoped package 의미: npm 조직·팀·프로젝트 네임스페이스로 묶인 패키지 집합 표기: @scope/package-name 형태 @nestjs/swagger, @angular/core 등 사용 이유 네임스페이스로 이름 충돌 회피 관련 패키지의 그룹화와 공개·비공개 관리 설치 npm install @nestjs/swagger 해석 이 경우 ‘@‘는 경로 별칭이 아닌 패키지 이름의 일부로 동작 tsconfig paths와 무관. Node/npm가 패키지 이름으로 직접 해석 ‘…’ 상대·절대 경로 import 상대 경로 ‘./’, ‘../’ 기준으로 현재 파일 위치에서 탐색 절대 경로 ‘/path’는 실행 환경마다 기준이 다름 브라우저 ESM에서는 오리진 기준 절대 URL 경로 해석 Node.js에서는 파일 시스템 루트 절대 경로로 해석되어 이식성 낮음 예시 import { User } from './models/User' import { calculate } from '../utils/math' 장점 추가 설정 없이 즉시 동작, 모든 환경 공통 동작 모델 모듈 간 물리적 의존 관계가 드러남 단점 디렉터리 깊어질수록 ../../../ 형태로 복잡도 상승 구조 변경 시 경로 대량 수정 발생 ‘#…’ 경로의 의미 ‘#{name}’ 표기는 두 가지 서로 다른 맥락에서 등장함. 혼동 주의 ...

January 23, 2026

CPU 자원 관점에서 보는 Node.js 이벤트 루프와 스레드풀 상호작용

개요 목표 이벤트 루프, 스레드풀, 커널이 실제 CPU 코어와 어떻게 상호작용하는지 CPU 관점에서 명확히 이해하기 Node.js가 어디서 CPU를 쓰고 어디서 기다리는지 구분해야 병목을 제대로 잡을 수 있음 CPU 코어와 OS 스레드의 물리적 의미 하드웨어와 OS 레벨 정의를 먼저 정리 CPU 코어 1개 ≈ 특정 시점에 물리적으로 실행 가능한 OS 스레드 1개 스레드 OS 스케줄러가 CPU를 할당하는 최소 단위 동시성 vs 병렬성 코어 1개면 수백 스레드도 시분할로 번갈아 실행되는 동시성 코어 여러 개일 때만 실제 병렬 실행 가능 CPU 관점의 핵심 비용 ...

January 22, 2026

nonce가 꼬인다? 트랜잭션 상태별 nonce의 변화

개요 Ethereum에서 트랜잭션 순서를 보장하는 핵심 메커니즘은 nonce임. 네트워크에서 자주 겪는 “nonce 꼬임"은 대개 트랜잭션 상태와 nonce 소비 규칙을 혼동해서 발생함. 아래는 EOA와 트랜잭션 관계, nonce 정의, 트랜잭션 상태별 nonce 변화 정리 EOA와 트랜잭션 Ethereum 계정은 두 종류로 구분 EOA, 개인 키로 서명해 트랜잭션 전송 가능 Contract Account, 스스로 트랜잭션 전송 불가, 외부에서 온 트랜잭션의 실행 흐름 내에서만 호출됨 트랜잭션을 보낸다는 것은 EOA가 서명 후 네트워크에 브로드캐스트한다는 의미. 컨트랙트는 내부 호출과 생성 같은 메시지 호출을 발생시킬 수 있지만 이는 트랜잭션이 아님. 최상위 트랜잭션의 발신자는 항상 EOA ...

January 21, 2026

이더리움 단위 정리: ETH, Gwei, Wei와 ERC-20 decimals 18

개요 이더리움 단위 체계는 10의 지수 기반으로 딱 떨어지게 설계됨 EVM은 부동소수점을 지원하지 않으므로 모든 값은 정수로 표현, 단위 나눔과 스케일링이 필수 단위 환산 1 ETH = 10^9 Gwei = 10^18 Wei 풀어서 보면 다음과 같음 1 ETH = 1,000,000,000 Gwei (10억 그웨이) = 1,000,000,000,000,000,000 Wei (100경 웨이) 용도별 구분 Wei: 최소 단위, 스마트 컨트랙트 내부 연산에 사용. Solidity에 소수점 개념 없음 Gwei: 10^9 Wei. 가스 가격 표시 단위로 사용, 사람이 읽고 비교하기 쉬움 Ether: 10^18 Wei. 지갑 잔고, 일상적 송금 금액 표시에 사용 개발자 상식: ERC-20 decimals = 18 ERC-20 토큰에서 decimals를 18로 두는 관례는 이더리움 기본 최소 단위(Wei) 스케일을 그대로 따름 의미: 토큰 1개가 10^18의 최소 단위로 분할 가능 예외: 스테이블 코인처럼 법정화폐 소수 자리를 맞추는 토큰은 decimals 6 등으로 설정하는 경우 있음 ...

January 20, 2026

ERC-4337 Account Abstraction의 장단점과 EntryPoint 병목 정리

개념/배경 Account Abstraction(AA, 계정 추상화)은 키 기반 EOA에 고정된 지갑 모델을 스마트 컨트랙트로 일반화해 UX를 끌어올리는 접근법. ERC-4337은 이를 프로토콜 변경 없이 애플리케이션 레이어에서 구현하는 표준. 목적은 블록체인을 몰라도 쓸 수 있는 경험을 제공하는 것. 대가로 추가 가스비와 인프라 복잡도가 뒤따름 장점 요약 가스비 대납과 가스 추상화 지원. Paymaster를 통해 사용자가 ETH 없이도 트랜잭션 가능. 서비스가 대납하거나 보유 토큰으로 지불하는 경로 구성 가능 소셜 복구 및 프로그래머블 보안. 시드 문구 분실 시 다중 승인 기반 복구, 전송 한도, 화이트리스트 등 정책 내장 가능 트랜잭션 배치. Approve → Swap 같은 연속 작업을 한 번의 서명으로 처리, 서명 피로와 왕복 비용 감소 세션 키. 제한된 권한과 기간으로 자동 서명 흐름 구성 가능. 게임 등 빈번한 액션에 유효 단점 요약 높은 가스비. EntryPoint를 경유하며 검증/실행 로직이 추가되어 오버헤드 발생. 메인넷에서는 체감 비용 큼, L2에서는 상대적으로 부담 완화 가능 인프라 복잡도 증가. 노드만으로 부족, Bundler·Paymaster·Aggregator 등 별도 컴포넌트 필요. 이들 장애 시 트랜잭션 정지 리스크 존재 DApp 호환성 이슈. EOA 전제 코드와 충돌 가능. EIP-1271 기반 서명 검증 경로를 지원하지 않는 레거시 DApp에서 로그인/서명 실패 발생 여지 지갑 생성 비용. AA 지갑은 컨트랙트이므로 최초 배포 비용 발생. 첫 트랜잭션 시 지연 배포로 UX 노출 최소화 가능 EntryPoint 병목 구조 ERC-4337에서는 사용자 요청(UserOperation)이 단일 싱글톤 컨트랙트인 EntryPoint를 통해 처리됨. Bundler가 여러 UserOp를 모아 EntryPoint의 handleOps를 호출하는 구조. 병목의 핵심은 서버 과부하라기보다 가스비 오버헤드와 검증 복잡도 증가 ...

January 19, 2026

TypeScript readonly 이해와 사용법, 배열·객체 읽기 전용 타입 지정

개념/배경 readonly는 TypeScript 전용 타입 수정자이며 JavaScript 런타임에는 존재하지 않음 컴파일 타임에만 효력이 있으며, 읽기 전용으로 선언된 배열·객체 속성을 수정하려는 코드에 대해 타입 오류를 발생시킴 핵심 개념 배열 또는 객체 속성의 변경 금지 의도를 타입 수준에서 명시 예를 들어 onChainResult: readonly bigint[]는 블록체인에서 읽어온 결과 배열이 이후 코드 흐름에서 변형되지 않음을 보장하려는 의도 표현 읽기 전용 제약은 타입 체크 시점에만 적용되며, 트랜스파일된 JavaScript에는 제약이 남지 않음 동작과 제한 읽기 전용 배열은 변경 메서드가 제거된 ReadonlyArray 형태로 다뤄짐 객체의 readonly 속성은 재할당 금지, 단 객체 참조 자체는 다른 값으로 교체 가능할 수 있으므로 설계 시 구분 필요 타입 수준 readonly는 얕은 불변성에 해당하는 경우가 많음. 중첩된 구조까지 불변으로 보장하려면 계층별로 readonly를 적용하거나 별도 불변 모델을 설계해야 함 ...

January 18, 2026

CEI 패턴 Checks-Effects-Interactions로 재진입 방어

개념/배경 CEI 패턴은 Checks-Effects-Interactions의 약자 스마트 컨트랙트 함수에서 실행 순서를 명확히 해 재진입 공격을 줄이는 코드 규칙 핵심은 검증 후 상태 변경을 먼저 완료하고, 외부 호출을 마지막에 수행하는 흐름 유지 3단계 순서 1. Checks (검증) ↓ 2. Effects (상태 변경) ↓ 3. Interactions (외부 호출)이 순서를 지키면 외부로 제어권이 나가기 전에 내부 상태가 이미 안전하게 반영됨 재진입 시도는 변경된 상태에 의해 자연스럽게 차단됨 예시로 이해하기 잘못된 순서 위험 function withdraw(uint256 amount) external { // 1. Checks require(balances[msg.sender] >= amount); // 2. Interactions ← 너무 빠름 (bool success, ) = msg.sender.call{value: amount}(""); require(success); // 3. Effects ← 너무 늦음 balances[msg.sender] -= amount; }문제점 ...

January 17, 2026

NestJS 전역 예외 필터와 표준 오류 응답 설계 가이드

개요 API 에러 응답을 일관된 JSON 포맷으로 통일하고, 비즈니스 예외와 프레임워크 예외를 한 경로로 수집하는 전역 예외 필터 설계와 구현 정리 핵심은 표준 에러 코드 정의, AppError 기반의 명시적 예외 던지기, GlobalExceptionFilter에서의 단일 포맷 출력, ValidationPipe 결과의 구조화, traceId 기반 상관관계 추적 요청 흐름 개요 요청 진입 → ValidationPipe 검증 검증 실패 → 전역 필터에서 표준 응답 변환 검증 통과 → Controller/Service 실행 비즈니스 로직 예외 → AppError 서브클래스 throw → 전역 필터 처리 알 수 없는 예외 → 500으로 표준 응답 변환 최종 응답 포맷은 단일 구조 유지 ...

January 16, 2026