typescript - Redux'te API istek akışlarını yönetmeyi basitleştirmek için typesafe-actions AsyncCreator kullanan genel async istek epikleri nasıl oluşturulur
Typescript redux ortamında epikleri asenkron eylemlerle ilişkilendirmek için en iyi mimariyi anlamaya çalışan bir acemiyim....
Belirli bir typesafe-actions AsyncCreator örneği için genel bir asenkron istek destanı oluşturmak mümkün mü?
Aşağıdaki kod ile deneme yaptım ama aksiyon yükünde tür bilgisi kayboluyor....filtrelenmiş aksiyonda yalnızca type özelliği tanınıyor....Aldığım transpile hatası ise...
Property 'payload' does not exist on type 'ReturnType<[TRequestPayload] extends [undefined] ? unknown extends TRequestPayload ? PayloadAC<TRequestType, TRequestPayload> : EmptyAC<TRequestType> : PayloadAC<TRequestType, TRequestPayload>>'.
const createAsyncEpic = <
TModel, // generic type for data payload
TRequestType extends string,
TRequestPayload extends ApiRequest<TModel>,
TSuccessType extends string,
TSuccessPayload extends ApiSuccess<TModel>,
TFailureType extends string,
TFailurePayload extends ApiFailure<TModel>
>(
asyncAction: AsyncActionCreator<
[TRequestType, TRequestPayload],
[TSuccessType, TSuccessPayload],
[TFailureType, TFailurePayload]
>,
) => {
const epic: Epic<RootAction, RootAction, RootState, Services> = (
action$,
state$,
{ apiService },
) =>
action$.pipe(
filter(isActionOf(asyncAction.request)),
switchMap(action =>
apiService
.api()
.all<TModel>(action.payload.url) // property payload unrecognised, only type property recognised here
.pipe(
map(response => asyncAction.success(response.data)),
catchError(error =>
of(
asyncAction.failure(error),
),
),
),
),
);
return epic;
};
Bunu, her kaynak için her bir API işlem türü için ayrı bir epic oluşturmak yerine başaran oldu mu? Örneğin, her akış için açıkça bir epic oluşturmak:
- [FETCH_TODO_REQUEST, FETCH_TODO_SUCCESS, FETCH_TODO_FAILURE],
- [POST_TODO_REQUEST, POST_TODO_BAŞARILI, POST_TODO_HATA].......,
- [POST_GETİRME_TALEBİ, POST_GETİRME_BAŞARILI, POST_GETİRME_HATASI],
- [PUT_POST_REQUEST, PUT_POST_SUCCESS, PUT_POST_FAILURE]........, vb.
Güncellenmiş bilgi
Biraz daha yakın.... veri modeli tipini kabul edecek şekilde yöntem fonksiyon imzası değiştirildi.
const createAsyncEpic = <
TModel // generic type for data payload model
>(
asyncAction: AsyncActionCreator<
[string, ApiRequest<TModel>],
[string, ApiSuccess<TModel | TModel[]>],
[string, ApiFailure<TModel>]
>,
) => {
const epic: Epic<RootAction, RootAction, RootState, Services> = (
action$,
state$,
{ courseServices, apiService },
) =>
action$.pipe(
filter(isActionOf(asyncAction.request)),
switchMap(action =>
apiService
.api()
.all<TModel>(action.payload.url)
.pipe(
map(resp =>
asyncAction.success({
request: action.payload, // Api request struct
response: resp, // Axios Response
}),
),
catchError(error =>
of(asyncAction.failure(action.payload.fail(error))),
),
),
),
);
return epic;
};
Şimdi farklı bir hata alınıyor:
ERROR in <path>/epics.ts
[tsl] ERROR in <path>/epics.ts(42,5)
TS2322: Type 'Observable<PayloadAction<TSuccessType, ApiSuccess<TModel | TModel[]>>>' is not assignable to type 'Observable<PayloadAction<actions.FETCH_COURSES_REQUEST, RequestingComponent> | PayloadAction<actions.FETCH_COURSES_SUCCESS, Course[]> | PayloadAction<constants.NOTIFY_ERROR, ErrorReport> | PayloadAction<string, ApiSuccess<Course>> | { ...; } | { ...; } | PayloadAction<...> | PayloadAction<...>>'.
Type 'PayloadAction<TSuccessType, ApiSuccess<TModel | TModel[]>>' is not assignable to type 'PayloadAction<actions.FETCH_COURSES_REQUEST, RequestingComponent> | PayloadAction<actions.FETCH_COURSES_SUCCESS, Course[]> | PayloadAction<constants.NOTIFY_ERROR, ErrorReport> | PayloadAction<string, ApiSuccess<Course>> | { ...; } | { ...; } | PayloadAction<...> | PayloadAction<...>'.
Type 'PayloadAction<TSuccessType, ApiSuccess<TModel | TModel[]>>' is not assignable to type 'PayloadAction<actions.FETCH_COURSES_REQUEST, RequestingComponent>'.
Type 'TSuccessType' is not assignable to type 'actions.FETCH_COURSES_REQUEST'.
Type 'string' is not assignable to type 'actions.FETCH_COURSES_REQUEST'.
Epik türü beyanında RootAction türleri ile kullanılan genel eylemi eşleştirmeye çalışmakla mı ilgili bir şey?
export declare interface Epic<Input extends Action = any, Output extends Input = Input, State = any, Dependencies = any> {
(action$: ActionsObservable<Input>, state$: StateObservable<State>, dependencies: Dependencies): Observable<Output>;
}
Cevap #1
Bunu çözdüm ve derlemeyi başardım. Sorun bir tür bildirimleri meselesiydi.
Typescript kullanırken, epic imzasında bildirilen eylem türleri, middleware kurulduğunda bildirilen tüm eylem türlerinin bir alt kümesi olmalıdır.
Yeni bir genel eylem örneği başlatmamıştım ve ayrıca bunu RootAction'a (tüm eylem türlerinin birliği) bir tür olarak eklememiştim. RootAction ayrıca yeniden yapılandırmadan önceki eski mimariden bazı eski eylem türlerini de içeriyordu.
Bunu yaptıktan ve epik imzamı yeniden düzenledikten sonra kod derlendi:
- Epik için giriş olarak kabul edilen eylem türlerinin alt kümesini belirtin
- Epik tarafından üretilen eylem türlerinin alt kümesini belirtin
Artık bir API'den kaynak listesi elde etmek için genel bir epikim var. Diğer epikler de patch, post, put işlemleri için takip edebilir.