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...
}