I can't figure out why Typescript is marking this as an error:
Property 'value' does not exist on type 'string | { value: string; label: string; }'.
Property 'value' does not exist on type 'string'.
Property 'label' does not exist on type 'string | { value: string; label: string; }'.
Property 'label' does not exist on type 'string'.
Code implementation:
type KeyParams="email"|"username"|"password"|"country"
type InputParams = Record<KeyParams, {error:boolean,value:string|{value: string, label: string}, msg:string}>
Inside React functional component:
const [inputs, setInputParams] = useState<InputParams>({"email":{error:false,value:"",msg:""},"username":{error:false,value:"",msg:""},"password":{error:false,value:"",msg:""},"country":{error:false,value:{value:"",label:""},msg:""}})
...
<input type="hidden" name="country" value={inputs.country.value.value}/>
<div className="w-100 h-100 relative flex items-center">
...
<span className="nowrap">{inputs.country.value.label}</span>
It doesn't mark that error when I only write the value inputs.country.value
inside the input and span elements
Couldn't find any similar question/solution for this specific case. Any suggestions?
CodePudding user response:
As Roberto explained in their comment, the problem is that inputs.country.value
could be either an object { value: string; label: string; }
or just a plain string
. That's because of how you've defined your InputParams
type:
type InputParams = Record<KeyParams, {
error: boolean,
value: string | {value: string, label: string}, // <-- this union right here
msg: string
}>
But in your actual component, inputs.country.value
is always the object.
This is a case where you're better off letting TypeScript infer the types for you. You'll get accurate type checking if you drop the generic <InputParams>
on your useState
hook:
const [inputs, setInputParams] = useState({"email":{error:false, ...
When you don't specify the state type, TypeScript will base it off of the initial value. So since you set the initial value for country
to {error:false,value:{value:"",label:""},msg:""}
, TypeScript infers the type of inputs.country.value
as
{ value: string; label: string; }
The type InputParams
is broader than the inferred type, so you are inadvertently widening the type.