So im trying to create my own custom hook to handle all my forms. For that im using the useReducer hook to handle al input changes and save them in the state.
The handleChange method recives two arguments (inputName, inputValue) and should update the value (inputValue) of the corresponding property (inputName) in the store trough the INPUT_CHANGE action. However Typescript doesn't infer the propertie name in field property of the payload of such action.
Reducer
export enum ActionTypes {
INPUT_CHANGE,
CLEAR,
}
type InputChangeAction<T extends object, K extends keyof T> = {
type: ActionTypes.INPUT_CHANGE;
payload: {
/* if T is {title: string, description?: string}
Then K should be "title" | "description" */
field: K;
value: string;
};
};
type ClearAction = {
type: ActionTypes.CLEAR;
};
type ReducerAction<T extends object, K extends keyof T> = ClearAction | InputChangeAction<T, K>;
export const FormHanldeReducer= <T extends object, K extends keyof T>(
state: T,
action: ReducerAction<T, K>,
) => {
switch (action.type) {
case ActionTypes.INPUT_CHANGE:
const {field, value} = action.payload;
return {...state, [field]: value};
case ActionTypes.CLEAR:
return (Object.keys(state) as Array<keyof typeof state>).reduce((newState, oldStateKey) => {
newState[oldStateKey] = '' as T[K];
return newState;
}, {} as typeof state);
default:
return state;
}
};
Hook
import {useReducer} from 'react';
import {useAppDispatch} from '../../store/hooks';
import {ActionTypes, FormHanldeReducer} from './FormHandleReducer';
export const useFormHandle = <T extends object, K extends keyof T>(initialState: T) => {
//redux hooks
const storeDispatch = useAppDispatch();
//state
const [formState, localDispatch] = useReducer(
FormHanldeReducer,
initialState,
);
//methods
const handleChange = (
inputName: keyof T,
inputValue: string,
) => {
localDispatch({
type: ActionTypes.INPUT_CHANGE,
payload: {
field: inputName, //Type 'string | number | symbol' is not assignable to type 'never'.
value: inputValue,
},
});
};
const save = () => {
//storeDispatch(actionToBeDespatched());
};
const dismiss = () => {
localDispatch({type: ActionTypes.CLEAR});
};
return {
formState,
handleChange,
save,
dismiss,
};
};
For some reason the field prop is never when should be a union of string literals
I feel I'm very close to the solution but i already browse so many pages. What can I do to solve this problem?