You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Immer中间件时为Zustand的set方法定义类型并保留自动补全

解决Zustand+Immer中间件下set方法的类型定义与自动补全问题

核心问题分析

启用Immer后,Zustand的set方法类型发生本质变化:回调参数从原状态类型变为Immer的WritableDraft<Store & ActionsObject>,且回调无需返回新状态(直接修改draft即可)。手动硬编码类型会丢失属性自动补全,复用非Immer版Setter类型则会触发类型不匹配错误。

解决方案

方案1:泛型函数自动推导类型(推荐)

让TypeScript自动从Zustand的Immer中间件中推导set和get的类型,避免手动硬编码:

import { create } from 'zustand';
import { immer } from 'zustand/middleware/immer';
import { WritableDraft } from 'immer';

// 定义状态与动作类型
type Store = {
  whateverProperty: string;
  // 其他状态属性
};

type Actions = {
  func: () => void;
  // 其他动作方法
};

// 用泛型约束set参数,确保回调接收WritableDraft类型的状态
function beginDraggingVertex<T extends Store & Actions>(
  set: (
    updater: ((state: WritableDraft<T>) => void) | Partial<T> | T,
    shouldReplace?: boolean
  ) => void,
  get: () => T,
  vertexID: string
) {
  return () => {
    set((store) => {
      // 此处自动补全store的所有属性
      store.whateverProperty = 'hi';
    });
  };
}

// 创建Store时传入泛型,自动推导内部set/get类型
export const useStore = create<Store & Actions>()(
  immer((set, get) => ({
    whateverProperty: 'initial',
    func: beginDraggingVertex(set, get, 'vertex-1')
  }))
);

方案2:手动定义正确的Immer版Setter类型

若需手动定义Setter类型,需引入Immer的WritableDraft并关联你的状态类型:

import { WritableDraft } from 'immer';

// 基于Store和Actions类型,定义Immer专属Setter
type ImmerSetter = (
  updater: 
    | (Store & Actions)
    | Partial<Store & Actions>
    | ((state: WritableDraft<Store & Actions>) => void),
  shouldReplace?: boolean
) => void;

type ImmerGetter = () => Store & Actions;

// 给外部函数指定正确类型
function beginDraggingVertex(set: ImmerSetter, get: ImmerGetter, vertexID: string) {
  return () => {
    set((store) => {
      // 自动补全恢复正常
      store.whateverProperty = 'hi';
    });
  };
}

方案3:结合Zustand内置类型工具

利用Zustand的StateSetter和Immer的Draft类型,快速构建正确的Setter类型:

import { StateSetter } from 'zustand';
import { Draft } from 'immer';

// 生成对应状态类型的Immer版Setter
type ImmerSetter = StateSetter<Draft<Store & Actions>>;

关键注意点

  • 必须正确导入Immer的WritableDraft或Draft类型,否则TypeScript无法识别draft状态的属性
  • 禁止混用非Immer版和Immer版的Setter类型,两者的回调逻辑与参数类型完全不同
  • 优先依赖TypeScript自动推导类型,减少手动硬编码带来的类型不一致问题

内容的提问来源于stack exchange,提问作者Vikms

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 01:05:33