React: setState()에서 'Excess Property Checks'를 사용하여 미묘한 버그를 방지

발행: (2026년 3월 9일 PM 01:27 GMT+9)
3 분 소요
원문: Dev.to

Source: Dev.to

문제

type State = {
  name: string,
  count: number,
}

// Initial state
const [state, setState] = useState({ name: 'Unknown', count: 0 });

// Intended update
function resetCount() {
  setState(state => ({
    ...state,
    count: 0,
  }));
}

// Oops – typo goes unnoticed
setState(state => ({
  ...state,
  cont: 0, // typo of `count`
}));

스프레드 연산자는 완전한 State 객체를 생성하기 때문에, 잘못 적힌 cont초과 속성으로 간주되고 타입 검사기가 오류를 발생시키지 않습니다. 이는 countpersonCount와 같이 이름을 바꿀 때 조용히 발생할 수 있으며, 미묘한 버그를 초래할 수 있습니다.

해결 방법: 업데이트 함수의 반환 타입에 주석 달기

setState에 전달되는 함수의 반환 타입을 명시적으로 선언하면 초과 속성 검사가 적용됩니다.

type State = {
  name: string,
  personCount: number, // renamed from `count`
};

const [state, setState] = useState({ name: 'Unknown', personCount: 0 });

function resetCount() {
  setState((state): State => ({
    ...state,
    count: 0, // ❌ TypeScript error: 'count' does not exist in type 'State'
  }));
}

이제 오타(또는 오래된 속성 이름)가 빌드 시점에 잡히게 됩니다.

다른 접근법

복잡한 상태에는 useReducer 사용

리듀서의 반환값에 명시적으로 타입을 지정하면 초과 속성 검사가 트리거됩니다.

// ❌ Inferred return type – no excess‑property checking
function reducer(state: State, action: Action) {
  /* ... */
}

// ✅ Explicit return type – catches incorrect properties
function reducer(state: State, action: Action): State {
  /* ... */
}

Immer를 활용한 mutable‑style 업데이트

Immer는 프록시를 제공해 “변경” 코드를 작성하면서도 불변성을 유지합니다. TypeScript는 여전히 속성 이름을 검증합니다.

Note: This isn’t the idiomatic React pattern and may reduce readability for some teams.

헬퍼 업데이트에 Partial 사용

// Helper that merges a partial state update
function update(partial: Partial) {
  setState(s => ({
    ...s,
    ...partial,
  }));
}

function resetCount() {
  update({ cont: 0 }); // ❌ Error: 'cont' does not exist in type 'State'
}

추가 자료

0 조회
Back to Blog

관련 글

더 보기 »