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.
