In one component, there is a <Link>
(from react-router-dom) passing an object in the state property.
Another component called ReceiverComponent
is receiving that object correctly. However, the code belows complains with the message:
Type 'PoorMansUnknown' is not assignable to type 'locationStateProps'. Type 'undefined' is not assignable to type 'locationStateProps'.ts(2322)
type locationStateProps = {
name: string;
}
function ReceiverComponent() {
const location = useLocation();
const myState: locationStateProps = location.state;
return (
<div>
{myState.name}
</div>
);
}
I need to provide a type for the state some way without this error. How to proceed?
You can also build your own state interface and cast it to it:
interface CustomState {
...
}
const location = useLocation()
const state = location.state as CustomState
There is a thread open on Github about this issue.
I implemented this solution mentioned on the thread and it worked.
interface Props extends RouteComponentProps<
{ myParamProp?: string }, // props.match.params.myParamProp
any, // history
{ myStateProp?: string }, // props.location.state.myStateProp
> {
myNormalProp: boolean;
}
For others who may end up here… I'm using React Router v6, which, as far as I can tell, no longer exports RouteComponentProps
(I installed @types/react-router and @types/react-router-dom — I see the type definition in the DefinitelyTyped files, but there is no export from react-router-dom
).
So, the way Location
is typed, I found myself unable to extend it in a way that would placate Typescript. However...
I wouldn't recommend as
casting, because it reduces the efficacy of TypeScript. Good news! You can use is
instead of as
to prove to TypeScript that a given element is indeed what you say it is. E.g.:
type LocationStateProps = {
name: string;
}
function ReceiverComponent() {
const location = useLocation();
const myState = location.state;
// note that you are defining the return type of this function using `is`
const hasNameProps = (state: object | null | LocationStateProps): state is LocationStateProps => {
// you use `as` here, but only so typescript doesn't yell at you while you access the property
// specifically to test if it is there
return (state as LocationStateProps).name !== undefined;
}
return (
<div>
{/**
* Now you can check to see if the prop exists. If it does, us it confidently, and TypeScript won't
* complain! But you're able to provide a fallback in case the value is, for some reason, not there.
* If you as-cast, you lose that opportunity. It's a little verbose, but it preserves the benefit of
* TypeScript... Type safety!
*/}
{hasNameProps(myState) ? myState.name : "No Name"}
</div>
);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With