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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.