Home > OS >  Object is possibly undefined react typescript in the dropdown component
Object is possibly undefined react typescript in the dropdown component

Time:09-27

I am creating a dropdown component but typescript throws several errors on the options.map and selectedOption.title cases:

import React, { useRef,useState, useEffect } from "react";
import useToggle from '../hooks/useToggle';
import  useDetectOutsideClick  from '../hooks/useOutsideClick';

import "./select.scss";
interface TProduct {
    title?: string;
    options?: [];
    getDropDownValue?: any;
  }

  interface TOption {
    title?: string;
    value?: string;
    id?: any;
  }

const Select = (props: TProduct) => {
    let { title, options, getDropDownValue } = props;
    const dropdownRef = useRef(null);
    const [visibility, setVisibility] =  useDetectOutsideClick(dropdownRef, false);
      const [selectedOption, setSelectedOption] = useState<TOption>({});
  
      return (
          
              <div
          className="base-select"
          ref={dropdownRef}
                  onClick={e =>  {
                      setVisibility(!visibility);
                  
                  }}
              >
                  <div className="selected-option">
                      <span
                          title={
                              selectedOption === ""
                                  ? title
                                  : selectedOption.title
                          }
                      >
                          {selectedOption === ""
                              ? title
                              : selectedOption.title.length <= 20
                              ? selectedOption.title
                              : selectedOption && selectedOption.title  && `${selectedOption.title.slice(0, 20)}`}
                      </span>
                      
                  </div>
                  {visibility && (
                      <div className="options">
                          <ul>
                      
                              {options
                                  .map((option) => (
                                      <li
                                          key={index}
                                          className={
                                             selectedOption && selectedOption ===       option
                                                  ? "active-option"
                                                  : ''
                                          }
                                          onClick={() => {
                        setSelectedOption(option);
                        getDropDownValue(option);
                       
                      }
                                          }
                                      >
                                          {option.title}
                                      </li>
                                  ))}
                          </ul>
                      </div>
                  )}
              </div>
      );
     };

    export default Select

So both looping of the list items and the titles are throwing error for options type and selectedOptions.title type Object is possibly undefined

What is wrong and how can be it fixed?

CodePudding user response:

It's fixable by safe typing your option and selectedOption with the ? operator from TS, and adding index to your options.map callback function.

<div
    className="base-select"
    ref={dropdownRef}
    onClick={e =>  {
      setVisibility(!visibility);
    }}
  >
    <div className="selected-option">
      <span
        title={
          selectedOption === ""
            ? title
            : selectedOption?.title
        }
      >
        {selectedOption === ""
          ? title
          : selectedOption?.title?.length <= 20
            ? selectedOption?.title
            : selectedOption?.title && `${selectedOption?.title?.slice(0, 20)}`}
      </span>

    </div>
    {visibility && (
      <div className="options">
        <ul>
          {options
            .map((option, index) => (
              <li
                key={index}
                className={
                  selectedOption?.id === option?.id
                    ? "active-option"
                    : ""
                }
                onClick={() => {
                  setSelectedOption(option);
                  getDropDownValue(option);
                }}
              >
                {option?.title}
              </li>
            ))}
        </ul>
      </div>
    )}
  </div>

I strongly suggest strictly typing the props of any react component that you are creating, TS is most usable here.

for instance:

type CustomSelectProps = {
  options?: Array<TOption>;
  title?: string;
  getDropDownValue?: (option: TOption) => void;
}
const Select: React.FC<CustomSelectProps> = (props) => {
  // ...component content...
}

  • Related