Why do makeStyles and createStyles have to be separate (Material UI + TypeScript)?

Viewed 1388

I've been using this construction that Material UI requires to deal with TypeScript issues a lot and it's really bugging me that every time I want to style a component I need to remember how to combine 2 different functions into something that will yield a hook (I could solve it with a snippet but that just never feels right to me):

const useStyles = makeStyles((theme: Theme) =>
  createStyles({
    ...styles
  })
);

So I tried of course to make it more DRY by just abstracting it away into 1 function but I can't seem to understand how to make the types work for this. Here's my clumsy attempt:

const makeUseStyles = (styleFunc: (th: Theme) => CSSProperties | CreateCSSProperties<{}>) =>
  makeStyles((theme: Theme) => {
    const st = styleFunc(theme);
    return createStyles(st);
  });

This creates 2 problems: createStyles doesn't accept st as an argument:

Type 'unknown' is not assignable to type 'PropsFunc<(value: JSSFontface, index: number, array: JSSFontface[]) => unknown, CreateCSSProperties<(value: JSSFontface, index: number, array: JSSFontface[]) => unknown>>'

And the function returned by makeUseStyles is suddenly expecting a required argument props of type (value: JSSFontface, index: number, array: JSSFontface[]) => unknown.

So I assume, since my attempt failed, that this is why there are 2 separate functions needed in the first place to appease TypeScript but it bothers me a lot that a compiler would dictate the abstractions (which it feels like it does all the time the moment I try to DRY out a bit my styling code). So my question is: why?

1 Answers

When you use or upgrade to TypeScript version > 3.4 you don’t need to call createStyle. The const assertions that became available in this version can defeat type widening. According to a code comment, the function createStyles will be removed in MaterialUI v5 (though it hasn't been removed from v5.0.0-alpha.23 yet).

I am indeed not experiencing any type widening and this is also confirmed by eps1lon in a github issue comment. The docs should definitely be updated.

Related