type AppState = {
user: {
firstName: string,
lastName: string,
}
}
const appState = {
user: {
firstName: 'John',
lastName: 'Doe',
}
}
type Action<T> = (state: AppState, payload: any) => T;
type Actions<T> = Record<string, Action<T>>;
type ActionOutput<T extends (...arg: any[]) => any> = T extends (arg: any, arg1: infer G) => any ? (payload: G) => any : (payload: any) => any;
type ActionsOutput<T> = Record<keyof T, ActionOutput<T>>; // how to pass acording function type?
function actionGenerator<T, G extends Actions<T>>(payload: G): {
actions: ActionsOutput<G>
} {
return {
actions: Object.entries(payload).reduce((prev, [key, callback]) => {
return {
...prev,
[key]: (actionPayload) => {
callback(appState, actionPayload);
},
}
}, {} as ActionsOutput<G>),
};
}
function updateUserDetailsAction(state: AppState, payload: {
firstName: string,
lastName: string,
}) {
return {
...state,
user: {
...payload,
}
}
}
const { actions } = actionGenerator<AppState, { updateNameAction: any }>({
updateNameAction
})
actions.updateUserDetailsAction({
test: '123'
})
How to infer
a function's argument. so when the above example's action
is invoked it will throw an error when the payload's type is not matched.