主题
迁移到 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" 中间件(如 combine 或 redux),请从 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
如果你没有将任何类型参数传递给 combine、devtools 或 subscribeWithSelector,则无需迁移。
¥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) => ..., ...).