Skip to content

迁移到 v4

¥Migrating to v4

唯一的重大变化是在类型中。如果你将 Zusand 与 TypeScript 或 JSDoc 类型注释一起使用,则本指南适用。否则,无需迁移。

¥The only breaking changes are in types. If you are using Zustand with TypeScript or JSDoc type annotations, this guide applies. Otherwise, no migration is required.

此外,建议先阅读新的 TypeScript 指南,以便更容易理解迁移。

¥Also, it's recommended to first read the new TypeScript Guide, so that the migration is easier to understand.

除了本迁移指南之外,你还可以检查 Zusand 存储库中从 v3 到 v4 的测试文件的 diff

¥In addition to this migration guide, you can also check the diff of the test files in the Zustand repository from v3 to v4.

create

适用的导入

¥Applicable imports

ts
import create from 'zustand'
import create from 'zustand/vanilla'

更改

¥Change

diff
- create:
-   < State
-   , StoreSetState = StoreApi<State>["set"]
-   , StoreGetState = StoreApi<State>["get"]
-   , Store = StoreApi<State>
-   >
-     (f: ...) => ...
+ create:
+   { <State>(): (f: ...) => ...
+   , <State, Mutators>(f: ...) => ...
+   }

迁移

¥Migration

如果你没有将任何类型参数传递给 create,则无需迁移。

¥If you are not passing any type parameters to create, no migration is required.

如果你使用的是 "leaf" 中间件(如 combineredux),请从 create 中删除所有类型参数。

¥If you are using a "leaf" middleware like combine or redux, remove all type parameters from create.

否则,将 create<T, ...>(...) 替换为 create<T>()(...)

¥Else, replace create<T, ...>(...) with create<T>()(...).

StateCreator

适用的导入

¥Applicable imports

ts
import type { StateCreator } from 'zustand'
import type { StateCreator } from 'zustand/vanilla'

更改

¥Change

diff
- type StateCreator
-   < State
-   , StoreSetState = StoreApi<State>["set"]
-   , StoreGetState = StoreApi<State>["get"]
-   , Store = StoreApi<State>
-   > =
-     ...
+ type StateCreator
+   < State
+   , InMutators extends [StoreMutatorIdentifier, unknown][] = []
+   , OutMutators extends [StoreMutatorIdentifier, unknown][] = []
+   , Return = State
+   > =
+     ...

迁移

¥Migration

如果你使用的是 StateCreator,则你可能正在编写中间件或使用 "slices" 模式。为此,请查看 TypeScript 指南的 编写中间件和高级用法常见秘诀 部分。

¥If you are using StateCreator, you are likely authoring a middleware or using the "slices" pattern. For that check the Authoring middlewares and advanced usage and Common recipes sections of the TypeScript Guide.

PartialState

适用的导入

¥Applicable imports

ts
import type { PartialState } from 'zustand'
import type { PartialState } from 'zustand/vanilla'

更改

¥Change

diff
- type PartialState
-   < T extends State
-   , K1 extends keyof T = keyof T
-   , K2 extends keyof T = K1
-   , K3 extends keyof T = K2
-   , K4 extends keyof T = K3
-   > =
-   | (Pick<T, K1> | Pick<T, K2> | Pick<T, K3> | Pick<T, K4> | T)
-   | ((state: T) => Pick<T, K1> | Pick<T, K2> | Pick<T, K3> | Pick<T, K4> | T)
+ type PartialState<T> =
+   | Partial<T>
+   | ((state: T) => Partial<T>)

迁移

¥Migration

PartialState<T, ...> 替换为 PartialState<T>,最好在 tsconfig.json 中打开 exactOptionalPropertyTypes

¥Replace PartialState<T, ...> with PartialState<T> and preferably turn on exactOptionalPropertyTypes in your tsconfig.json:

json
{
  "compilerOptions": {
    "exactOptionalPropertyTypes": true
  }
}

我们不再使用技巧来禁止将 { foo: undefined } 分配给 Partial<{ foo: string }>。相反,我们依靠用户打开 exactOptionalPropertyTypes

¥We're no longer using the trick to disallow { foo: undefined } to be assigned to Partial<{ foo: string }>. Instead, we're relying on the users to turn on exactOptionalPropertyTypes.

useStore

适用的导入

¥Applicable imports

ts
import { useStore } from 'zustand'
import { useStore } from 'zustand/react'

更改

¥Change

diff
- useStore:
-   { <State>(store: StoreApi<State>): State
-   , <State, StateSlice>
-       ( store: StoreApi<State>
-       , selector: StateSelector<State, StateSlice>,
-       , equals?: EqualityChecker<StateSlice>
-       ): StateSlice
-   }
+ useStore:
+   <Store, StateSlice = ExtractState<Store>>
+     ( store: Store
+     , selector?: StateSelector<State, StateSlice>,
+     , equals?: EqualityChecker<StateSlice>
+     )
+       => StateSlice

迁移

¥Migration

如果你没有将任何类型参数传递给 useStore,则无需迁移。

¥If you are not passing any type parameters to useStore, no migration is required.

如果是这样,建议删除所有类型参数,或者将 store 类型而不是状态类型作为第一个参数传递。

¥If you are, it's recommended to remove all the type parameters, or pass the store type instead of the state type as the first parameter.

UseBoundStore

适用的导入

¥Applicable imports

ts
import type { UseBoundStore } from 'zustand'
import type { UseBoundStore } from 'zustand/react'

更改

¥Change

diff
- type UseBoundStore<
-   State,
-   Store = StoreApi<State>
- > =
-   & { (): T
-     , <StateSlice>
-         ( selector: StateSelector<State, StateSlice>
-         , equals?: EqualityChecker<StateSlice>
-         ): U
-     }
-   & Store
+ type UseBoundStore<Store> =
+   & (<StateSlice = ExtractState<S>>
+       ( selector?: (state: ExtractState<S>) => StateSlice
+       , equals?: (a: StateSlice, b: StateSlice) => boolean
+       ) => StateSlice
+     )
+   & S

迁移

¥Migration

UseBoundStore<T> 替换为 UseBoundStore<StoreApi<T>>,将 UseBoundStore<T, S> 替换为 UseBoundStore<S>

¥Replace UseBoundStore<T> with UseBoundStore<StoreApi<T>>, and UseBoundStore<T, S> with UseBoundStore<S>

UseContextStore

适用的导入

¥Applicable imports

ts
import type { UseContextStore } from 'zustand/context'

更改

¥Change

diff
- type UseContextStore

迁移

¥Migration

改用 typeof MyContext.useStore

¥Use typeof MyContext.useStore instead

createContext

适用的导入

¥Applicable imports

ts
import createContext from 'zustand/context'

更改

¥Change

diff
  createContext:
-   <State, Store = StoreApi<State>>() => ...
+   <Store>() => ...

迁移

¥Migration

createContext<T>() 替换为 createContext<StoreApi<T>>(),将 createContext<T, S>() 替换为 createContext<S>()

¥Replace createContext<T>() with createContext<StoreApi<T>>(), and createContext<T, S>() with createContext<S>().

combine, devtools, subscribeWithSelector

适用的导入

¥Applicable imports

ts
import { combine } from 'zustand/middleware'
import { devtools } from 'zustand/middleware'
import { subscribeWithSelector } from 'zustand/middleware'

更改

¥Change

diff
- combine:
-   <T, U>(...) => ...
+ combine:
+   <T, U, Mps, Mcs>(...) => ...

- devtools:
-   <T>(...) => ...
+ devtools:
+   <T, Mps, Mcs>(...) => ...

- subscribeWithSelector:
-   <T>(...) => ...
+ subscribeWithSelector:
+   <T, Mps, Mcs>(...) => ...

迁移

¥Migration

如果你没有将任何类型参数传递给 combinedevtoolssubscribeWithSelector,则无需迁移。

¥If you are not passing any type parameters to combine, devtools, or subscribeWithSelector, no migration is required.

如果是这样,请删除所有类型参数,因为它们是自动推断的。

¥If you are, remove all the type parameters, as they are inferred automatically.

persist

适用的导入

¥Applicable imports

ts
import { persist } from 'zustand/middleware'

更改

¥Change

diff
- persist:
-   <T, U = Partial<T>>(...) => ...
+ persist:
+   <T, Mps, Mcs, U = T>(...) => ...

迁移

¥Migration

如果你传递了任何类型参数,请将其删除,因为它们是自动推断的。

¥If you are passing any type parameters, remove them as they are inferred automatically.

接下来,如果你传递了 partialize 选项,则无需执行迁移的进一步步骤。

¥Next, if you are passing the partialize option, there is no further steps required for migration.

如果你没有传递 partialize 选项,你可能会看到一些编译错误。如果你没有看到任何函数,则无需进一步迁移。

¥If you are not passing the partialize option, you might see some compilation errors. If you do not see any, there is no further migration required.

部分状态的类型现在是 T 而不是 Partial<T>,这与默认 partialize(即身份(s => s))的运行时行为一致。

¥The type of partialized state is now T instead of Partial<T>, which aligns with the runtime behavior of the default partialize, which is an identity (s => s).

如果你看到一些编译错误,你必须自己查找并修复错误,因为它们可能表明代码不健全。或者,解决方法是将 s => s as Partial<typeof s> 传递给 partialize。如果你的部分状态确实是 Partial<T>,则不应该遇到任何错误。

¥If you see some compilation errors, you have to find and fix the errors yourself, because they might be indicative of unsound code. Alternatively, the workaround will be passing s => s as Partial<typeof s> to partialize. If your partialized state is truly Partial<T>, you should not encounter any bugs.

运行时行为没有改变,只有类型现在正确了。

¥The runtime behavior has not changed, only the types are now correct.

redux

适用的导入

¥Applicable imports

ts
import { redux } from 'zustand/middleware'

更改

¥Change

diff
- redux:
-   <T, A>(...) => ...
+ redux:
+   <T, A, Mps, Mcs>(...) => ...

迁移

¥Migration

如果你没有将任何类型参数传递给 redux,则无需迁移。

¥If you are not passing any type parameters to redux, no migration is required.

如果是这样,请删除所有类型参数,并仅注释第二个(操作)参数。也就是说,用 redux((state, action: A) => ..., ...) 替换 redux<T, A>((state, action) => ..., ...)

¥If you are, remove all the type parameters, and annotate only the second (action) parameter. That is, replace redux<T, A>((state, action) => ..., ...) with redux((state, action: A) => ..., ...).

Zustand v5.0 中文网 - 粤ICP备13048890号