React:在 setState() 中使用“额外属性检查”以避免细微错误

发布: (2026年3月9日 GMT+8 12:27)
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 被视为多余属性,类型检查器不会报错。这在重命名时(例如把 count 改为 personCount)可能悄悄出现,并导致细微的 bug。

解决方案:为更新函数标注返回类型

显式声明传给 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

显式为 reducer 的返回值标注类型同样会触发多余属性检查。

// ❌ 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 进行可变式更新

Immer 提供了一个代理,使你能够编写“变异”代码,同时保持不可变性。TypeScript 仍会校验属性名。

注意: 这不是 React 的惯用模式,可能会降低某些团队的可读性。

使用 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

相关文章

阅读更多 »