Two groups of conditional props trigger "boolean" is not assignable to "false"

70 views Asked by At

I have a group of consistent types and two groups of conditional props like so:


export interface Props {
    label: string
    children?: ReactNode | undefined
}

export type OpacityConditionalProp =
    | {
            hasOpacitySlider: true
            opacitySliderState: number | number[]
            opacitySliderSetter: Dispatch<SetStateAction<number | number[]>>
      }
    | {
            hasOpacitySlider?: false | undefined
            opacitySliderState?: undefined
            opacitySliderSetter?: undefined
      }

export type VisibilityConditionalProp =
    | {
            hasVisibilityToggle: true
            isVisible: boolean
            onChangeVisibility: (v: boolean) => void
      }
    | {
            hasVisibilityToggle?: false | undefined
            isVisible?: undefined
            onChangeVisibility?: undefined
      }

And in the component I declare it like:

const LayerItem: FC<Props & OpacityConditionalProp & VisibilityConditionalProp> = ({
    label,
    hasOpacitySlider,
    opacitySliderState,
    opacitySliderSetter,
    isVisible,
    onChangeVisibility,
    hasVisibilityToggle,
    children,
})

It works well when I use it like this:

<LayerItem
    hasOpacitySlider={false}
    hasVisibilityToggle={false}
    label="Range statistics"
>

or like this

<LayerItem
    isVisible={show}
    label="Contours"
    opacitySliderSetter={setOpacity}
    opacitySliderState={opacity}
    hasOpacitySlider
    hasVisibilityToggle
    onChangeVisibility={setShow}
>

or like this

<LayerItem
    hasOpacitySlider={false}
    isVisible={showBathy}
    label="Bathymetry contours"
    hasVisibilityToggle
    onChangeVisibility={setShowBathy}
>

However, it throws an error when I use it like this:


const hasOrthoData = Boolean(orthoData)

<LayerItem
    hasOpacitySlider={hasOrthoData}
    hasVisibilityToggle={hasOrthoData}
    isVisible={showOrthoLayer}
    opacitySliderSetter={setOrthoLayerOpacity}
    opacitySliderState={orthoLayerOpacity}
    onChangeVisibility={setShowOrthoLayer}
    label="Orthophoto"
>

Error

I expect that if I pass true to hasVisibilityToggle or to hasOpacitySlider, it will figure out when to use which type and what to render. However, it doesn't work well when I pass ternary operators to the props of the component, complaining with that error.

Maybe there is a better and clean way to achieve this?

I managed to get this working, but I am not pleased with the solution:

<LayerItem
    {...(hasOrthoData
        ? ({
                hasOpacitySlider: true,
                hasVisibilityToggle: true,
                isVisible: showOrthoLayer,
                opacitySliderSetter: setOrthoLayerOpacity,
                opacitySliderState: orthoLayerOpacity,
                onChangeVisibility: setShowOrthoLayer,
                label: 'Orthophoto',
          } as Props & OpacityConditionalProp & VisibilityConditionalProp)
        : ({
                label: 'Orthophoto',
          } as Props))}
>
1

There are 1 answers

0
Federico Alecci On

You are on the right path AFAIK. TypeScript compiler isn't smart enough to detect at compile time the different combination of properties you are sending to the LayerItem component.

You could make it look cleaner anyways

const layerItemProps: OpacityConditionalProp = hasOrthoData
    ? {
            hasOpacitySlider: true,
            opacitySliderState: 1
            ...otherProps
        }
    : {
            hasOpacitySlider: false
            ...otherProps
        }

return (
    <LayerItem
        {...layerItemProps}
        label="Orthophoto"
    />
);

label prop will go anyways independent of the OpacityConditionalProps.