anti-05. 4칸 고정인데 string[] — 튜플 누락
빈도: 25건 중 9+건 — 카드번호 4칸·만료일 2칸은 고정 길이인데 string[]로 선언해 컴파일러가 길이를 보장하지 못한다. 더 나아가 훅 시그니처까지 string[]로 좁아지면 단일 string인 CVC를 [""] 배열로 감싸는 역방향 전염까지 발생한다.
패턴 한 줄
cardNumbers: string[] / expirationPeriod: string[] 형태로 타입을 열어두면, cardNumbers[0]을 사용하는 모든 코드가 런타임에서야 undefined 가능성을 만난다.
AS-IS 코드 (8기 PR 발췌)
🔍 읽기 전에
“내 타입 정의에서
string[]을 검색해보자. 그 배열의 최대/최소 길이는 컴파일러가 알고 있는가?”
사례 A — interface에 string[] 그대로
PR #515 — src/types.ts
// src/types.ts
interface CardInfo {
cardNumbers: string[]; // 항상 4칸
expirationPeriod: string[]; // 항상 2칸
cvc: string;
cardBrand: CardBrand;
}리뷰어 코멘트:
“string[] 대신 튜플(cardNumbers 4칸, expirationPeriod 2칸)“
사례 B — 단일 문자열을 굳이 배열로 감싸기
PR #524 — PR body 회고:
“cvc는 사실상 단일 문자열인데, useInputHandle 훅이 string[]을 받기 때문에 [""] 배열로 감싸서 사용했습니다.”
훅의 입력 타입이 string[]로 좁혀져 있어, 원래 string인 값까지 배열로 감싸는 역방향 전염이 일어났다.
리뷰어 eastroots92가 한 줄로 짚었다.
“string, string[] 둘다 고려 가능하게 해볼 수 있을까요?” → 훅 입력 타입 재검토 요청
이 사례가 보여주는 것은 — 고정 길이 배열을 string[]로 표현한 결정 이 훅 시그니처 와 컴포넌트 분리(anti-06)와 통째 lifting(anti-08) 까지 모두 같은 형태의 모양을 갖도록 잡아당긴다는 점이다. 타입은 단순한 안전망이 아니라 코드의 모양을 결정한다.
사례 C — 같은 형태, 다른 PR
PR #498 PR #513 PR #516 PR #518 — cardNumbers: string[] 패턴 반복.
사례 D — 한걸음 더 — cardBrand: string
PR #505 — CardPreview.tsx
리뷰어 코멘트:
“
cardBrand: string이 너무 넓습니다.”
PR #514 도 같은 신호:
“리터럴 유니온 타입을 쓰면 잘못된 값이 들어오는 것을 컴파일 타임에 잡을 수 있어요!” →
type NetworkBrand = 'visa' | 'master'제안
타입 좁히기 누락은 길이뿐 아니라 값의 집합에도 적용된다.
리뷰어 피드백 (실제 인용)
- PR #505
CardPreview.tsx:4— “cardBrand: string이 너무 넓습니다.” - PR #513
types.ts:6— “튜플 타입을 사용하면 컴파일 타임에 길이를 보장할 수 있어요!” - PR #514
CardNetworkBrand.tsx:5— “리터럴 유니온 타입을 쓰면 잘못된 값이 들어오는 것을 컴파일 타임에 잡을 수 있어요!” - PR #515
types.ts:3— “string[] 대신 튜플(cardNumbers 4칸, expirationPeriod 2칸)” - PR #524
useInputHandle.ts:7— “string, string[] 둘다 고려 가능하게 해볼 수 있을까요?”
토론 질문
cardNumbers: string[]타입을 가진 함수에서cardNumbers[3]을 안전하게 사용하려면 — 어떤 런타임 검사가 필요한가? 그 검사 없이 사용하면 어떤 위험이 있는가?cardNumbers: [string, string, string, string](튜플)로 바꾸면 — 그 검사 중 어떤 것이 컴파일러에게 옮겨지는가?cardBrand: string을'visa' | 'master' | null로 좁히면 — 코드의 어떤 분기가 작성하지 않아도 되는 분기로 바뀌는가?
연관 카드
- Q8 — TypeScript 타입 좁히기 — never 회피 — 같은 주제, 고민 관점
- Q2 — state 구조 — 모순을 막는 표현 형태




