1

I am trying to apply TypeScript in my ReactJS project. I am starting apply it to one of my components but somehow I am having hard time applying typescript when a components accepts object with properties as its props.

Here is my code

interface iValue { results: string[] | number[]; } interface DropDownInputInt { name: string; value: iValue | string; multiple: boolean; } const DropDownInput = ({ name, value, multiple }: DropDownInputInt) => { return ( <> <Dropdown name={name} value={multiple && value ? value.hasOwnProperty('results') ? value.results : value : value } /> </> ) }) 

For my props named "value" I am accepting 2 possible inputs, string or an object(with 'results' key and can have both an array string or number)

enter image description here

See image below for a sample of props.value that has a string value.

enter image description here

Not sure why but currently my VSCode is showing errors when I tried to use value.results. See image below for the error.

enter image description here

UPDATE

I tried to incopmperate some answers from

interface iValue { results: (string | number | boolean)[]; } interface DropDownInputInt { name: string; value: iValue | boolean | number | string; multiple: boolean; } const DropDownInput = ({ name, value, multiple }: DropDownInputInt) => { return ( <> <Dropdown name={name} value={ multiple && value ? typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ? value : value.results : typeof value === 'object' && value } /> </> ) }) 

But I am still getting errors, now its pointing to value property in my Dropdown

enter image description here

But when I check the property that being accepted by the "Dropdown" component

enter image description here

Thanks in advance

2
  • If your value contains a string, .results doesn't exists. value isn't a object. You can set the type: interface iValue { results: string[] | number[]| string; } interface DropDownInputInt { name: string; value: iValue; multiple: boolean; } and always save on value like a object. Commented Mar 30, 2020 at 8:08
  • I cannot put string in my results because in the 2nd screenshot I posted the 'results' key doesnt exists Commented Mar 30, 2020 at 16:49

3 Answers 3

2

value can be string or object, when it is a string it still has hasOwnProperty because of boxing. Potentially it might have results field and fit iValue type, in practice you cannot assign a property to primitive string but TS does not take it into account.

More predictable check is needed, for example

value={multiple && value ? typeof value === "object" && value.hasOwnProperty('results') ? value.results : value : value 

or it could be reversed

value={multiple && value ? typeof value === "string" ? value : value.results : value 
Sign up to request clarification or add additional context in comments.

4 Comments

Just woke up, ill try this one TIA
@Shlag I did some edit in my code but somehow it throwing a different error.
@Billy that is because if you pass multiple=false the value passes as is and its type is value: iValue | boolean | number | string; and that is not compatible with the Dropdown props
Hi @Shlang, I added this on my code "typeof value === 'object' && value" to check if its an object if the multiple is false but it still giving me error
0

I think I solve it using. Thank you @Shlang for point out the problem

interface iValue { results: (string | number | boolean)[]; } interface DropDownInputInt { name: string; value: iValue | boolean | number | string; multiple: boolean; } const DropDownInput = ({ name, value, multiple }: DropDownInputInt) => { return ( <> <Dropdown name={name} value={ multiple && value ? typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean' ? value : value.results : typeof value === 'object' && value } /> </> ) }) 

Comments

-1

TS is not smart enough to figure this out on its own (i.e. to figure out that it's not a string, but an iValue) so you need to help it out using a type guard, e.g.

 function isIValue(value: string | iValue): value is iValue { return typeof value !== "string" } 

The value is iValue annotation essentially tells the Typescript type system that if the function returns true, the argument is of type iValue.

Hence you can then do:

 <Dropdown name={name} value={(multiple && isIValue(value) && value.results) || value} /> 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.