2

Hi al I'm having a small typing problem with a component I'm trying to fix:

interface ChildrenProps {
  exit: (force?: boolean) => void;
  state: StateValue;
}
interface Props {
  // https://reactjs.org/docs/render-props.html
  children: (childrenProps: ChildrenProps) => {};
  close: () => void;
  isOpen: boolean;
  state: StateValue;
}
const ModalDialog: React.FC<Props> = function (props) {
  const { children, close, isOpen } = props;
  const layers = useContext(LayersContext);
  const [state, send] = useMachine(modelDialogMachine, {
    actions: {
      close,
    },
  });
  ...
  const childrenProps = { state: state.value, exit: sendExitEvent };

  return ReactDOM.createPortal(
    <ModalDialogContext.Provider value={contextValue}>
      <Backdrop className={state.value} onClick={handleBackdropClick}>
        <Dialog onClick={handleDialogClick}>{children(childrenProps)}</Dialog>
      </Backdrop>
    </ModalDialogContext.Provider>,
    container,
  );
};

At <Backdrop className={state.value} onClick={handleBackdropClick}> I'm getting:

 Type 'StateValue' is not assignable to type 'string | undefined'.
      Type 'StateValueMap' is not assignable to type 'string'.
  Overload 2 of 2, '(props: StyledComponentPropsWithAs<"div", DefaultTheme, {}, never>): ReactElement<StyledComponentPropsWithAs<"div", DefaultTheme, {}, never>, string | ... 1

Where StateValue are types from import { StateValue } from 'xstate' the xstate state machine library.

The classname is used to switch between styles:

export const Backdrop = styled.div`
  &.entering {
  ...

How can I resolve this typing error?Hi al I'm having a small typing problem with a component I'm trying to fix:

interface ChildrenProps {
  exit: (force?: boolean) => void;
  state: StateValue;
}
interface Props {
  // https://reactjs.org/docs/render-props.html
  children: (childrenProps: ChildrenProps) => {};
  close: () => void;
  isOpen: boolean;
  state: StateValue;
}
const ModalDialog: React.FC<Props> = function (props) {
  const { children, close, isOpen } = props;
  const layers = useContext(LayersContext);
  const [state, send] = useMachine(modelDialogMachine, {
    actions: {
      close,
    },
  });
  ...
  const childrenProps = { state: state.value, exit: sendExitEvent };

  return ReactDOM.createPortal(
    <ModalDialogContext.Provider value={contextValue}>
      <Backdrop className={state.value} onClick={handleBackdropClick}>
        <Dialog onClick={handleDialogClick}>{children(childrenProps)}</Dialog>
      </Backdrop>
    </ModalDialogContext.Provider>,
    container,
  );
};

At <Backdrop className={state.value} onClick={handleBackdropClick}> I'm getting:

No overload matches this call.
  Overload 1 of 2, '(props: Pick<Pick<Pick<DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "slot" | "style" | ... 252 more ... | "onTransitionEndCapture"> & { ...; }, "ref" | ... 254 more ... | "onTransitionEndCapture"> & Partial<...>, "ref" | ... 254 more ... | "onTransitionEndCapture"> & { ...; } & { ...; }): ReactElement<...>', gave the following error.
    Type 'StateValue' is not assignable to type 'string | undefined'.
      Type 'StateValueMap' is not assignable to type 'string'.
  Overload 2 of 2, '(props: StyledComponentPropsWithAs<"div", DefaultTheme, {}, never>): ReactElement<StyledComponentPropsWithAs<"div", DefaultTheme, {}, never>, string | ... 1 more ... | (new (props: any) => Component<...>)>', gave the following error.

Where StateValue are types from import { StateValue } from 'xstate' the xstate state machine library.

The classname is used to switch between styles:

export const Backdrop = styled.div`
  &.entering {
  ...

If I console.log the state.value I do get strings:

ModalDialog.js:79 exited
ModalDialog.js:79 entering
ModalDialog.js:79 entered

Typing for StateValue and StateValueMap

export declare type StateValue = string | StateValueMap;

export interface StateValueMap {
    [key: string]: StateValue;
}

How can I resolve this typing error?

Carrein
  • 3,231
  • 7
  • 36
  • 77

1 Answers1

0

If you know it'll be a string, you can type cast it: className={state.value as string}. Just bear in mind that more complex machines can return an object (i.e. if you have a parallel machine) so the cast is only valid if you don't plan to ever need the StateValueMap variant. If you do, you can run into the Objects are not valid as a React child error at run time if you, for example, did <p>{state.value}</p>.

sunny-mittal
  • 499
  • 5
  • 12