Consider this code:
IAppStateProps.ts
:
import {INoteProps} from "./INoteProps";
export interface IAppStateProps {
notesData: INoteProps[];
}
then use it here:
useAppState.ts
:
import {INoteProps} from "./interfaces/INoteProps";
import {IAppStateProps} from "./interfaces/IAppStateProps";
export const useAppState = (): IAppStateProps => {
const [notesData, setNotesData] = useState<INoteProps[]>([]);
...more code
return {
notesData
}
};
My question is, since I defined the return type of useAppState
to be IAppStateProps
, and it knows that notesData
should return INoteProps[]
, is it necessary to define the return type again in const [notesData, setNotesData] = useState<INoteProps[]>([]);
?
since I defined the return type of useAppState to be IAppStateProps, and it knows that notesData should return INoteProps[], is it necessary to define the return type again in const [notesData, setNotesData] = useState<INoteProps[]>([]);?
Yes. TypeScript can't infer it in the direction you're describing. If you leave the type argument off the call to useState
and you use an empty array like that as the intial value, TypeScript will infer never[]
as the type, which means you wouldn't be able to call setNotesData
with real data:
// Stand-in for `INoteProps`, since it's not defined in the question
interface INoteProps {
something: string;
}
// ...
export const useAppState = (): IAppStateProps => {
const [notesData, setNotesData] = useState([]);
useEffect(() => {
setNotesData([
{something: "cool"} // <== Error: Type '{ something: string; }' is
// not assignable to type 'never'. (2322)
])
}, []);
return {
notesData
};
};
If you want, you can infer it the other way, though, by leaving off the return type annotation on useAppState
:
export const useAppState = () => {
const [notesData, setNotesData] = useState<INoteProps[]>([]);
useEffect(() => {
setNotesData([
{something: "cool"} // <== Works
])
}, []);
return {
notesData
};
};
TypeScript will infer the return type as { notesData: INoteProps[]; }
. Since TypeScript's type system is structural (based on the shape of types) not nominal (based on the names of types), that's the same as IAppStateProps
.
You may not want to do that, though, since an erroneous edit that accidentally changes the return type of the function wouldn't be caught by TypeScript. In practice, I find inferring the return type is fine for really short, simple functions, but for anything beyond that I need the safety net of specifying what the return should be so edits accidentally changing it get caught early. Your mileage may vary. :-)