I have a Typescript project that uses redux and redux-persist. Is it possible to use Typescript for a redux-persist migration configuration? The main difficulty comes down to this: If you have a Typescript-typed root redux state, it typically/always represents the latest version of your state (not necessarily what was previously persisted). In the context of a migration, how do you represent the data that’s being read from persistence in a typed manner, knowing it doesn’t match the latest version of your state? Some details:
Here is the Typescript API of redux-persist for data migrations:
export interface MigrationManifest {
[key: string]: (state: PersistedState) => PersistedState;
}
export interface PersistedState { _persist?: PersistState }
export interface PersistState { version: number; rehydrated: boolean; }
Makes sense, you provide a MigrationManifest which has keys that are version numbers and values that are functions that receive the persisted state and return a new persisted state. Since PersistedState is just an interface, it seems you could have one incoming type and return a different type (in cases where your data schema changed).
So let's say I have the following type as my root persistent store type. It conforms to the PersistedState interface:
type RootState = {
name: string,
address: Address,
_persist?: PersistState
}
type Address = {
street: string
city: string
}
At some point in the future, I update my model to:
type RootState = {
name: string,
address: Address,
_persist?: PersistState
}
type Address = {
vacant: boolean
}
And I need to provide a migration which would look something like:
const manifest: MigrationManifest = {
1: (state: PersistedState) => {
const persistedState = state as ???
const migratedState: RootState = migrateState(persistedState)
return migratedState
}
}
Where I'm struggling is with getting a type for the incoming state (where my cast to ??? is). In a simple example like this, it would be easy to maintain a record of each version of my state, import and use them as necessary:
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
}
}
In practice, it's not that simple; I have a complex state tree, not all of which is defined in a central and easy to version location.
One solution I can dream up, but I don't know is possible, would be to somehow create a version of my RootState type with all of the intermediate type aliases and interface names "dissolved". Something like:
type RootState_v0 = {
name: string,
address: {
street: string
city: string
},
_persist?: {
version: number,
rehydrated: boolean
}
}
If I could create that in some automatic way, it would be easy and convenient to keep and use in migrations.
Any idea if that is possible, or any other suggestions about how to effectively use Typescript in react-redux migrations?