AncientSwordRage
AncientSwordRage

Reputation: 7617

Passing optional props through a spread 'props'

I've got some nested components (so that there is a separation of concern) that pass optional components through:

const FooBarMenu = ({ match }) => {
  return <div>
    {isFooBarLoadable ? (
      <FooBarLoader action={action} label='Foo Bar' selector={getLoadedFooBar}>
        <FooBar />
      </FooBarLoader>
    ) : <FooBarPlaceholder />}
  };

then the <FooBarLoader> looks like:


type FooBarLoaderProps = {
  action: Function,
  children?: React.ReactNode,
  selector: (state: MyProjectState) => MightError<string>,
  props: {} // <-- this worked, but is where issues start
}

const FooBarLoader = ({
  action,
  children = undefined,
  selector,
  ...props
}: FooBarLoaderProps) => {

// do stuff to load FooBars (or not)

const error = useSelector(compose(getErrorFromState, selector));
// etc...

return (
  <LoadingSpinner
    error={error}
    {...props}
  >
    {children}
  </LoadingSpinner>
)

}

and our LoadingSpinner looks like:

type LoadingSpinnerProps = {
  children?: React.ReactNode,
  error?: string,
  label?: string,
  // etc... many more optional props
};

const LoadingSpinner = ({
  children = undefined,
  error = undefined,
  label = '...',
  // etc... many more props with defaults
}: LoadingSpinnerProps) => {
  // figure out if we needs to show an error etc
  // show label
  // Show spinning progress
};

the issue is now I'm converting the javascript component FooBarMenu to use typescript, I'm seeing an issue where FooBarLoader is expecting label as part of the props, but that doesn't work with how the types are being declared?

I'm seeing 'property label does not exist on type 'IntrinsicAttributes & FooBarLoaderProps'. Trying to use props: Partial<{ label: string }> in FooBarLoaderProps still shouts that it doesn't know what label is.

If I have :

type FooBarLoaderProps = {
  action: Function,
  children?: React.ReactNode,
  selector: (state: MyProjectState) => MightError<string>,
  label?: string,
  props: {},
}

And I provide label it complains I don't have a props prop (even though before it seemed fine?). Instead I need to mark both as optional, which seems like it's missing the point that label is part of props.

How should I be declaring the FooBarLoaderProps type, to include the optional props in props?

Upvotes: 0

Views: 214

Answers (1)

Konrad
Konrad

Reputation: 24661

You probably didn't get the second error, because the first one was preventing it.

You declare props, but you don't use it. ...props in the component is not the same as props in your types. You can name the first one as you want.

Your type should look like this:

type FooBarLoaderProps = {
  action: Function,
  children?: React.ReactNode,
  selector: (state: MyProjectState) => MightError<string>,
  label?: string,
  // list other props here
}

or

type FooBarLoaderProps = {
  action: Function,
  children?: React.ReactNode,
  selector: (state: MyProjectState) => MightError<string>,
  label?: string,
} & LoadingSpinnerProps

Upvotes: 1

Related Questions