[英]Typescript-typed redux-persist MigrationManifest?
我有一个使用redux和redux-persist的Typescript项目。 是否可以将Typescript用于redux-persist迁移配置? 主要困难归结于此:如果您具有Typescript类型的根redux状态,则它通常/总是表示状态的最新版本(不一定是以前保留的状态)。 在迁移的上下文中,如果知道与状态的最新版本不匹配,那么如何以持久化的方式表示从持久性读取的数据? 一些细节:
这是redux-persist用于数据迁移的Typescript API:
export interface MigrationManifest {
[key: string]: (state: PersistedState) => PersistedState;
}
export interface PersistedState { _persist?: PersistState }
export interface PersistState { version: number; rehydrated: boolean; }
有道理,您提供了一个MigrationManifest
,其中包含的键是版本号,而值是接收持久状态并返回新的持久状态的函数。 由于PersistedState
只是一个接口,因此看来您可能只有一种传入类型,而返回另一种类型(在数据模式更改的情况下)。
假设我具有以下类型作为我的根持久存储类型。 它符合PersistedState
接口:
type RootState = {
name: string,
address: Address,
_persist?: PersistState
}
type Address = {
street: string
city: string
}
在将来的某个时候,我将模型更新为:
type RootState = {
name: string,
address: Address,
_persist?: PersistState
}
type Address = {
vacant: boolean
}
我需要提供一个看起来像这样的迁移:
const manifest: MigrationManifest = {
1: (state: PersistedState) => {
const persistedState = state as ???
const migratedState: RootState = migrateState(persistedState)
return migratedState
}
}
我苦苦挣扎的是获取传入状态的类型(我转换成???
位置)。 在像这样的简单示例中,可以轻松保存我的状态的每个版本的记录,并根据需要导入和使用它们:
import { RootState as RootState_v0 } from 'types_v0.ts'
const manifest: MigrationManifest = {
1: (state: PersistedState) => {
const persistedState = state as RootState_v0
const migratedState: RootState = migrateState(persistedState)
return migratedState
}
}
实际上,这不是那么简单。 我有一个复杂的状态树,不是所有的状态树都定义在中央且易于版本控制的位置。
我可以梦想得到的解决方案,但我不知道可行,将以某种方式创建具有所有中间类型别名和接口名称“ dissolved”的RootState
类型的版本。 就像是:
type RootState_v0 = {
name: string,
address: {
street: string
city: string
},
_persist?: {
version: number,
rehydrated: boolean
}
}
如果我可以通过某种自动方式创建它,那么在迁移中保留和使用它将会很容易和方便。
是否有可能的任何想法,或有关如何在react-redux迁移中有效使用Typescript的其他建议?
在某些时候,您必须指定什么版本的版本。 但是,您可以使用查找类型和条件类型来简化以分散方式构建数据结构的过程。 这是一个例子:
interface MigrationManifest {
[key: string]: (state: PersistedState) => PersistedState;
}
interface PersistedState { _persist?: PersistState }
interface PersistState { version: number; rehydrated: boolean; }
//////
type VERSION_3 = 3;
type VERSION_2 = VERSION_3 | 2;
type VERSION_1 = VERSION_2 | 1;
type VERSION_0 = VERSION_1 | 0;
interface TypeBundleBase {
root: {};
address: {};
phoneNumber: {};
}
interface RootV0<B extends TypeBundleBase> {
name: string;
address: B["address"];
phoneNumber: B["phoneNumber"];
_persist?: PersistState;
}
interface ContactsV2<B extends TypeBundleBase> {
address: B["address"];
phoneNumber: B["phoneNumber"];
}
interface RootV2<B extends TypeBundleBase> {
name: string;
contacts: ContactsV2<B>;
_persist?: PersistState;
}
interface AddressV0<B extends TypeBundleBase> {
street: string;
city: string;
}
interface AddressV1<B extends TypeBundleBase> {
vacant: boolean;
}
type PhoneNumberV0<B extends TypeBundleBase> = string;
interface PhoneNumberV3<B extends TypeBundleBase> {
countryCode: string;
countryPhoneNumber: string;
}
interface Types<V extends VERSION_0, B extends TypeBundleBase> {
root: [V] extends [VERSION_2] ? RootV2<B> : RootV0<B>;
address: [V] extends [VERSION_1] ? AddressV1<B> : AddressV0<B>;
phoneNumber: [V] extends [VERSION_3] ? PhoneNumberV3<B> : PhoneNumberV0<B>;
}
interface FixedTypes<V extends VERSION_0> extends Types<V, FixedTypes<V>> { }
type Root<V extends VERSION_0> = FixedTypes<V>["root"];
declare function migrateState1(state: Root<VERSION_0>): Root<VERSION_1>;
declare function migrateState2(state: Root<VERSION_1>): Root<VERSION_2>;
declare function migrateState3(state: Root<VERSION_2>): Root<VERSION_3>;
const manifest: MigrationManifest = {
1: (state: PersistedState) => {
const persistedState = state as Root<VERSION_0>;
const migratedState: Root<VERSION_1> = migrateState1(persistedState);
return migratedState;
},
2: (state: PersistedState) => {
const persistedState = state as Root<VERSION_1>;
const migratedState: Root<VERSION_2> = migrateState2(persistedState);
return migratedState;
},
3: (state: PersistedState) => {
const persistedState = state as Root<VERSION_2>;
const migratedState: Root<VERSION_3> = migrateState3(persistedState);
return migratedState;
}
}
我可能没有想到这种方法可能会出现故障,但是值得一试。 我怀疑我是第一个想到此方法的人,但是对先前的工作进行了几次快速的网络搜索都没有成功。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.