strblr
strblr

Reputation: 950

Missing properties when inferring props from component

So basically, I found myself using this pattern a lot with Material UI to avoid using inline styles or the hook or hoc styling api :

const TestStepper = styled(props => (
  <MobileStepper classes={{ progress: "progress" }} {...props} />
))(({ theme }) => ({
  backgroundColor: "transparent",
  "& > .progress": {
    width: "100%",
    marginRight: theme.spacing(3)
  }
}));

I cannot rely on a stable MuiMobileStepper-progress class because I have nested themes, so I use this trick to get stable nested selectors.

I wanted to encapsulate this behaviour in a utility function :

export function styledNested<
  P extends { classes: Record<string, string> },
  C extends Array<keyof P["classes"]>
>(Component: ComponentType<P>, ...classes: C) {
  return styled((props: P) => (
    <Component
      {...props}
      classes={classes.reduce((acc, key) => ({ ...acc, [key]: key }), {})}
    />
  ));
}

But when trying it :

const TestStepper = styledNested(
  MobileStepper,
  "progress"
)(({ theme }) => ({
  backgroundColor: "transparent",
  "& > .progress": {
    width: "100%",
    marginRight: theme.spacing(3)
  }
}));

I get the following TS error :

TS2345: Argument of type '(props: MobileStepperProps) => Element' is not assignable to parameter of type 'ComponentType<{ classes: Record<string, string>; }>'.
 Type '(props: MobileStepperProps) => Element' is not assignable to type 'FunctionComponent<{ classes: Record<string, string>; }>'.
  Types of parameters 'props' and 'props' are incompatible.
   Type 'PropsWithChildren<{ classes: Record<string, string>; }>' is missing the following properties from type 'MobileStepperProps': backButton, nextButton, steps

CodeSandbox link

How could I fix this ?

Upvotes: 0

Views: 284

Answers (1)

diedu
diedu

Reputation: 20815

If you ctrl + click in the classes prop when writing a <MobileStepper ... tag, the IDE takes you to the StyledComponentProps interface, so it seems that's the correct interface to extend from:

P extends StyledComponentProps,

But then you'll have a problem with C being never[] type because StyledComponentProps has clasess as an optional prop, this is solved by using Required over P when getting the keys

C extends Array<keyof Required<P>["classes"]>

https://codesandbox.io/s/lively-star-zm7lx?file=/src/App.tsx

Upvotes: 1

Related Questions