I am experiencing with using TypeScript in React states. My intention is to use objects with strict types instead of several separate useState
statements, and with desirably no additional classes to represent these object structures (only interfaces). I have the following scenario:
const [state, setState] = useState<IStateType>(..code1..);
In the above line IStateType
extends another interface, let us call that IStateSubType
:
export interface IStateType extends IStateSubType {...}
Since objects with IStateSubType
are instantiated more than once in my project, I would create a function to initialise these objects in order to reduce code redundancy:
function getEmptyStateSubType(): IStateSubType(..code2..);
In this function code2 part would define the properties required by IStateSubType
and return the resulting object. I would call getEmptyStateSubType()
in code1 part, then I would extend its returning objects' properties with missing ones required by IStateType
as below:
const [state, setState] = useState<IStateType>(
(): IStateType => {
const tmpValue: IStateSubType = getEmptyStateSubType();
const value: IStateType = {
...tmpValue,
foo: bar
};
return value;
}
);
Using the above implementation I did achieve my goal to strictly use types in both the state and the function and there are also no redundant lines, but at the end of the day not only did the number of lines increased in my code, but I also feel that readability decreased greatly while unnecessary complexity increased. I was wondering if there are better solutions to achieve my goals: maintain readability and enforce type usage. How to implement this with shorter and more readable code?
CodePudding user response:
This should do
const [state, setState] = useState<IStateType>(
() => ({...getEmptyStateSubType(), foo: 'bar' })
);
But nothing stops you from creating a getStateType
function
const getStateType =
(o: Omit<IStateType, keyof IStateSubType>): IStateType =>
(({...getEmptyStateSubType(), ...o}))
const [state, setState] = useState<IStateType>(getStateType({ foo: 'bar' }));
CodePudding user response:
Though my question was quite vague, for anyone facing similar issues in the future allow me to share my second attempt for implementing this:
const [state, setState] = useState<IStateType>(
() => { // I removed the type, since it is already enforced by useState
const value: IStateType = {
...getEmptyStateSubType(), // I used spread on method return value
foo: bar
};
return value;
}
);