मैं ऐसा करना चाहता हूँ:

export const selectPlacesForCurrentCustomer = createSelector(
   selectAllPlaces,
   selectedCustomerId,
   (places: Place, customer_id: string) => places.filter((place) => place.customer === customer_id)
) 

हालांकि जब मैं ऐसा करता हूं, तो मुझे यह त्रुटि मिलती है:

'MemoizedSelector' प्रकार का तर्क 'Selector' प्रकार के पैरामीटर के लिए असाइन करने योग्य नहीं है।

यहां मेरे आवेदन का एक सरलीकृत संस्करण है जो इस मुद्दे को पुन: उत्पन्न करता है। https://stackblitz.com/ संपादित करें/angular-10-ngrx-issue?file=src/app/reducers/index.ts

यहाँ मेरे राज्य का एक स्क्रीनशॉट है। मैं इन दो चीजों को मिलाना चाहता हूं: यहां छवि विवरण दर्ज करें

**************** पृष्ठभूमि ******************

मेरे पास दो अलग फीचर स्टोर हैं। प्रत्येक स्टोर NGRX/Entity का उपयोग करता है।

  1. स्थानों
  2. ग्राहक

मैं एक चयनकर्ता बनाना चाहता हूं जो दोनों से डेटा खींचता है। यहाँ दोनों मॉडलों के लिए एक सरलीकृत इंटरफ़ेस है:

export interface Place {
_id: string;
customer: string;
...
}

export interface Customer {
_id: string;
}

ग्राहक मॉड्यूल

ग्राहक सुविधा के कई स्टोर हैं। मैं इस सुविधा को अपने ग्राहक मॉड्यूल में इस प्रकार आयात करता हूं:

 StoreModule.forFeature(fromCustomer.customersFeatureKey, fromCustomer.reducers)

ग्राहक सुविधा स्थिति इस तरह दिखती है:


export interface CustomerState {
    [fromCustomers.customerFeatureKey]: fromCustomers.State; //I'm want pull data from here!!
    [fromPaymentMethods.paymentmethodFeatureKey]: fromPaymentMethods.State;
    [fromInvoices.invoiceFeatureKey]: fromInvoices.State;
    [fromSubscriptions.subscriptionFeatureKey]: fromSubscriptions.State;
}

// This is what I pass to the `forFeature` method in my customer module. 
export function reducers(state: CustomerState | undefined, action: Action) {
  return combineReducers({
    [fromCustomers.customerFeatureKey]: fromCustomers.reducer,
    [fromPaymentMethods.paymentmethodFeatureKey]: fromPaymentMethods.reducer,
    [fromInvoices.invoiceFeatureKey]: fromInvoices.reducer,
    [fromSubscriptions.subscriptionFeatureKey]: fromSubscriptions.reducer
  })(state, action);
}

अगर हम fromCustomers.State स्थिति की जांच करते हैं, तो यह ऐसा दिखता है:

export interface State extends EntityState<Customer> {
  selectedCustomerId: string | null; // --> This is the first piece of data I'm trying to select.
  loaded: boolean;
  loading: boolean;
  processing: boolean;
}
 
export const adapter: EntityAdapter<Customer> = createEntityAdapter<Customer>({
    selectId: customer => customer._id,
    sortComparer: false
});
 
export const initialState: State = adapter.getInitialState({
    selectedCustomerId: null,
    loaded: false,
    loading: false,
    processing: false
});

...

जैसा कि हम ऊपर देख सकते हैं, यह मैं अंत में EntityAdapter सेटअप कर रहा था। इस सुविधा से मैं जिस महत्वपूर्ण डेटा का चयन करने का प्रयास कर रहा हूं वह है: selectedCustomerId

मेरे पास इस सुविधा में एक चयनकर्ता है जो इस तरह दिखता है:

export const selectedCustomerId = createSelector(
    selectCustomersEntitiesState,
    (state) => state.selectedCustomerId
)

प्लेस मॉड्यूल

अब जब हमारे पास ग्राहक मॉड्यूल का सारांश हो गया है, तो चलिए स्थान सुविधा पर चलते हैं

ग्राहक मॉड्यूल के समान, मैं इसे स्थान मॉड्यूल फ़ाइल में आयात कर रहा हूं।

मेरा प्लेस स्टेट इस तरह दिखता है:

export interface PlaceState {
    [fromPlaces.placeFeatureKey]: fromPlaces.State;
    //[fromSearch.searchFeatureKey]: fromSearch.State; // This is where you should add search for assignments
}

export interface State extends fromRoot.State {
  [placesFeatureKey]: PlaceState;
}

// This is what I pass to the `forFeature` method in my place module. 
export function reducers(state: PlaceState | undefined, action: Action) {
  return combineReducers({
    [fromPlaces.placeFeatureKey]: fromPlaces.reducer,
  })(state, action);
}

यदि हम [fromPlaces.placeFeatureKey] में उतरते हैं तो आप देखेंगे कि मैं स्थान मॉडल के लिए EntityAdapter कहाँ स्थापित कर रहा हूँ।

export interface State extends EntityState<Place> {
  selectedPlaceId: string | null;
  loaded: boolean;
  loading: boolean;
  processing: boolean;
}
 
export const adapter: EntityAdapter<Place> = createEntityAdapter<Place>({
    selectId: place => place._id,
    sortComparer: false
});
 
export const initialState: State = adapter.getInitialState({
    selectedPlaceId: null,
    loaded: false,
    loading: false,
    processing: false
});

मेरे पास सभी स्थानों के लिए चयनकर्ता है:

export const {
  selectIds: selectPlaceIds,
  selectEntities: selectPlaceEntities,
  selectAll: selectAllPlaces, // --> This second thing I'm trying to select. 
  selectTotal: selectTotalPlaces,
} = fromPlaces.adapter.getSelectors(selectPlacesEntitiesState);

जगह से चयनकर्ता सुविधा जिसमें मेरी रुचि है selectAllPlaces है।

मुझे आशा है कि आप अभी भी मेरे साथ हैं। **अब जब मैंने पृष्ठभूमि सेट कर ली है, तो मैं यह बताना चाहूंगा कि मुझे क्या करने की उम्मीद है, लेकिन मैं यह नहीं समझ सकता कि कैसे।

********** मैं यह करना चाहता हूं: **********

export const selectPlacesForCurrentCustomer = createSelector(
   selectAllPlaces,
   selectedCustomerId,
   (places: Place, customer_id: string) => places.filter((place) => place.customer === customer_id)
) 

हालांकि जब मैं ऐसा करता हूं, तो मुझे यह त्रुटि मिलती है:

'MemoizedSelector' प्रकार का तर्क 'Selector' प्रकार के पैरामीटर के लिए असाइन करने योग्य नहीं है।

2
calbear47 5 फरवरी 2021, 09:50
कृपया साझा करें कि आपने selectAllPlaces को कहाँ परिभाषित किया है। यदि संभव हो तो क्या आप त्रुटि को पुन: उत्पन्न कर सकते हैं? अगर, stackblitz.com/edit/…
 – 
Owen Kelvin
7 फरवरी 2021, 13:51
मैंने एक स्टैकब्लिट्ज शामिल किया है जो इस मुद्दे को दोबारा शुरू करता है।
 – 
calbear47
8 फरवरी 2021, 01:18
समस्या के रूप में जोड़ा गया टाइपप्रति टैग TS में प्रकार बेमेल से संबंधित है
 – 
Owen Kelvin
8 फरवरी 2021, 14:20

1 उत्तर

सबसे बढ़िया उत्तर

समस्या डिबगिंग

आइए इस कोड को डीबग करने का प्रयास करें जहां त्रुटि फेंकी जा रही है

export const selectPlacesForCurrentCustomer = createSelector(
  selectAllPlaces,
  selectedCustomerId,
  (customer_id: string, places: Place[]) =>
    places.filter(place => place.customer === customer_id)
);

नीचे IDE का एक स्क्रीनशॉट है जो दर्शाता है कि त्रुटि selectedCustomerId लाइन में है

Initial Error

त्रुटि में हम नीचे की रेखा को भी नोटिस करते हैं

प्रॉपर्टी '[customersFeatureKey]' 'import("/~/src/app/place/reducers/index").State' टाइप में मौजूद नहीं है, लेकिन 'import("/~/src/app/customer/reducers/ अनुक्रमणिका")। राज्य'।

अब मापदंडों को पलटने की कोशिश करते हैं

export const selectPlacesForCurrentCustomer = createSelector(
  selectedCustomerId,
  selectAllPlaces,
  (places: Place[], customer_id: string) =>
    places.filter(place => place.customer === customer_id)
);

अब हम देखते हैं कि त्रुटि अब selectedCustomerId पर नहीं बल्कि अब selectAllPlaces पर है और त्रुटि बदल गई है

Property '[placesFeatureKey]' is missing in type 'import("/~/src/app/customer/reducers/index").State' but required in type 'import("/~/src/app/place/reducers/index").State'.

Inverted Parameters

व्याख्या

नीचे createSelector() की परिभाषा दी गई है

createSelector(selectors: [Selector<State, S1>, Selector<State, S2>], projector: (s1: S1, s2: S2) => Result): MemoizedSelector<State, Result>

कुछ ध्यान दें, राज्य Selector<State, S1> और Selector<State, S2> में समान State है

यह त्रुटि क्यों फेंकी जा रही है, यह समझाने के लिए नीचे डॉक्स से एक उद्धरण दिया गया है

createSelector का उपयोग राज्य से कुछ डेटा का चयन करने के लिए किया जा सकता है, जो एक ही राज्य के कई स्लाइस के आधार पर होता है।

एक ही राज्य के कई हिस्सों की पंक्ति पर ध्यान दें।

तो आपके मामले में आप places से दो अलग State, State पास कर रहे हैं, जिसमें एक '[placesFeatureKey]' और State customers से है, जिसमें ' [customersFeatureKey]' जो असंगत हैं

समाधान

विकल्प 1 - एक ही प्रकार का टाइपकास्ट State


export const selectPlacesForCurrentCustomer = createSelector(
  selectAllPlaces as MemoizedSelector<State, Place[]>,
  selectedCustomerId as MemoizedSelector<State, string>,
  (places: Place[], customer_id: string) =>
    places?.filter(place => place.customer === customer_id)
);

इस समाधान का नमूना डेमो देखें

विकल्प 2 - चयनकर्ता बनाने के बजाय देखने योग्य स्ट्रीम में पाइपिंग का उपयोग करें

आप घटक या सेवा में दो धाराओं को संयोजित करने के लिए बस पाइपिंग का उपयोग कर सकते हैं

  allPlaces$ = this.store.select(selectAllPlaces);
  selectedCustomerId$ = this.store.select(selectedCustomerId);
  selectPlacesForCurrentCustomer$ = combineLatest([
    this.allPlaces$,
    this.selectedCustomerId$
  ]).pipe(
    map(([places, customer_id]) =>
      places.filter(place => place.customer === customer_id)
    )
  );

इस समाधान का नमूना डेमो देखें

विकल्प 3 - एक चयनकर्ता बनाएं जो पूरे राज्य का चयन करता है और संबंधित फ़ंक्शन को निकालता है

export const selectPlacesForCurrentCustomer = (state: State) => {
  const places = selectAllPlaces(state as any);
  const customerId = selectedCustomerId(state as any);
  return places.filter(place => place.customer === customerId);
};

नमूना डेमो देखें

1
Owen Kelvin 8 फरवरी 2021, 14:15
आपके विस्तृत उत्तर के लिए धन्यवाद। मैं पुरस्कार देने से पहले कल इस बारे में और सोचूंगा। समाधान 1 पर अनुवर्ती प्रश्न -> क्या यह समाधान अभी भी संस्मरण का लाभ उठाएगा? मैं ऐसा सोचूंगा क्योंकि हम सिर्फ राज्य की कास्टिंग कर रहे हैं।
 – 
calbear47
8 फरवरी 2021, 09:05
मेरा मानना ​​​​है कि यह निश्चित होने के बावजूद मैंने मानों को टाइपकास्ट करने के लिए MemoizedSelector के समाधान को बदल दिया है।
 – 
Owen Kelvin
8 फरवरी 2021, 13:38