Home > OS >  Typscript: Property 'value' does not exist on type 'string | { value: string; label:
Typscript: Property 'value' does not exist on type 'string | { value: string; label:

Time:10-25

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.

  • Related