簡體   English   中英

打字稿類型的redux-persist MigrationManifest?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM