У меня есть следующие создатели действий:
/** simply captures the string literal type */
function actionType<T extends string, U>(type: T, u: U) {
return Object.assign({}, { type }, u);
}
// ------------------------------------
// Action Creators
// ------------------------------------
const ACTION_CREATORS = {
toggleFilter: (params: { filterValueKey: string; filterKey: string; filterValue: string }) => {
const { filterKey, filterValue, filterValueKey } = params;
return actionType('FILTERS_TOGGLE', {
payload: {
filterValueKey,
filterKey,
filterValue
}
});
},
deleteFilter: (params: { filterValueKey: string }) => {
const { filterValueKey } = params;
return actionType('FILTERS_DELETE', {
payload: {
filterValueKey
}
});
},
searchFilterValues: (params: { activeFilterKey: string; query: string }) => {
const { query, activeFilterKey } = params;
return actionType('FILTERS_QUERY_VALUES', {
payload: {
query,
activeFilterKey
}
});
}
};
, и я хотел бы написать
type ActionHandlers<T extends {
[actionCreator: string]: (...args: any[]) => { type: string }
}> = { /* ... */ };
, который добавит правильные наборы для "обработчиков действий"объект, подобный приведенному ниже:
const ACTION_HANDLERS: ActionHandlers<typeof ACTION_CREATORS > = {
FILTERS_TOGGLE: (state, action) => {
action.payload.filterValueKey // this key is typed
const newState = { ...state };
return newState;
},
FILTERS_DELETE: () => {} /* ... */,
FILTERS_QUERY_VALUES: (state, action) => {
action.payload.query // this is also typed and typed differently
const newState = { ...state };
return newState;
}
}
Пока я могу захватывать имена типов действий и получать возвращаемые типы создателей действий, но я застрял в этой точке:
type Action<T extends { type: string }> = T;
type ActionCreator<T extends string> = (...params: any[]) => { type: T };
type MapToNames<T extends { [key: string]: ActionCreator<any> }> = {
[P in keyof T]: T[P] extends ActionCreator<infer U> ? U : never
};
type ActionNames<T extends { [key: string]: ActionCreator<any> }> = MapToNames<
T
>[keyof MapToNames<T>];
type RemoveFunctions<T extends { [key: string]: (...args: any[]) => { type: string } }> = {
[P in keyof T]: T[P] extends (...params: any[]) => Action<infer U> ? U : never
};
type Names = ActionNames<typeof ACTION_CREATORS>;
// type Names = "FILTERS_TOGGLE" | "FILTERS_DELETE" | "FILTERS_QUERY_VALUES"
type NoFunctions = RemoveFunctions<typeof ACTION_CREATORS>;
Любые идеи будут с благодарностью!