簡體   English   中英

泛型鍵入給定類型的商店

[英]Generic typing a store of a given type

我正在創建一個商店應該能夠擴展的自定義 Redux 商店。 我的目標是這樣的:

class BaseStore<T> { 
    public state$: Observable<StoreState<T>>;
    ...
    // other helpers and the like
}

StoreState看起來像:

export type ErrorState = Record<string, any>;
export type LoadableState<T> = {
  data: T;
  loading: boolean;
  error: ErrorState;
};
export type StoreState<T> = Record<string, Partial<LoadableState<T>>>;

但我無法正確輸入。 這可行,但如果您想在商店中有兩件商品,如下所示:

{ // this object represents the store which consists of LoadableStates 
      something: { // I want to type the "slices" in the store
        data: { // and also to be able to type what is in data
          todos: [] 
        },
        loading: false,
        error: {}
      },
      somethingElse: {
        data: {
          items: []
        },
        loading: false,
        error: {}
      }
}

整個事情都崩潰了; 意思是,我不能繼續輸入以下內容:

interface SomethingState {
  email?: string;
  username?: string;
}

interface SomethingElseState {
  todos?: Array<Record<string,string>>;
  saveSuccess?: Record<string, string | boolean>;
}

interface MyStoreState {
  something?: SomethingState;
  somethingElse?: SomethingElseState;
}

class MyStore extends BaseStore<MyStoreState> {
  ...
  public getEmail(): Observable<string> {
    return this.state$.pipe(map(state => state.something.data.email))
  }
}

有任何想法嗎? 不能說我已經使用過 generics,所以這將是一次很棒的學習體驗。

編輯:映射類型似乎有一個缺點。 商店的update() function 不起作用:

// my implementation for updating the store

public set(nextState: StoreState<T>): void {
  this.state$.next(nextState);
}

public update(storeSlice: string, partialState: Partial<LoadableState<T>>): void {
    if (!this.stateValue[storeSlice]) {
      throw Error('Path does not exist in the store');
    }

    const currentState = this.stateValue[storeSlice];
    const nextState = merge(currentState, partialState); // lodash's merge

    this.set({ [storeSlice]: { ...nextState } }); // ERROR: Argument of type '{ [x: string]: any; }' is not assignable to parameter of type 'StoreState<T>'
  }

我不確定“整個事情都崩潰了”到底是什么意思(通常是一個最小可重復的例子,它表明你的意思比文字更有幫助),但假設你想跟蹤state的每個鍵及其相應屬性的data類型,我建議使用映射類型來表示StoreState<T>以表示這些鍵/數據關系的 object 類型T

type StoreState<T> = { [K in keyof T]: Partial<LoadableState<T[K]>> };

然后,假設BaseStore<T>有一個構造函數來設置其state屬性:

class BaseStore<T> {
    constructor(public state: StoreState<T>) { }
}

您應該能夠使用 object 構建一個:

const bs = new BaseStore({
    something: {
        data: {
            todos: [1, 2, 3] // 🤷‍♂️
        },
        loading: false,
        error: {}
    },
    somethingElse: {
        data: {
            items: ["a", "b", "c"] // 🤷‍♀️
        },
        loading: false,
        error: {}
    }
});

您會看到構造的 object 的類型已被推斷(通過映射類型的推斷),如下所示:

/*
const bs: BaseStore<{
    something: {
        todos: number[];
    };
    somethingElse: {
        items: string[];
    };
}>*/

所以這里推斷的T{something: {todos: number[]}; somethingElse: {items: string[]};} {something: {todos: number[]}; somethingElse: {items: string[]};}我想,你想要的。

希望有幫助; 祝你好運!

鏈接到代碼

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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