Search code examples
reactjstypescriptmaterial-uiemotiontss

Unable to find out the types needed to add to parameter of custom function


I'm using tss-react and MUI package and I'm unable to figure what to set the types for custom function I've written which basically merges all my common styles and the specific styles I want for a component.

Due to this I'm getting TypeScript errors when accessing my classes object. (eg: Property 'colorRed' does not exist on type 'Record<never, string>'.

What types to add in the getUseStyles.ts file so that I get both the types from commonStyles file and my component styles ? (Basically typescript/editor should be able to intellisense when accessing classes object keys like classes.colorRed or classes.colorBlue)

CodeSandbox

// File: Test.tsx
const useStylesHook = getUseStyles(  // Merging component styles and common styles
  (theme) => {
    return {
      colorRed: {
        color: 'red',
      },
      colorBlue: {
        color: 'blue',
      },
    }
})

export default function Test() {
  const { classes, cx } = useStylesHook()
  return (
    <h1 className={cx(classes.colorRed, classes.padding20, classes.colorBlue)}>
      Testing this color
    </h1>
  )
}
// File: commonStyles.ts
export const commonStyles = (theme) => {
  return {
    padding20: {
      paddingTop: '20px',
    },
  }
}
// File: getUseStyles.ts
export const getUseStyles = (
  styles: any, // What types to add here ?
  customStyles?: any,
) => {
  return makeStyles()((theme) => {
    return {
      ...commonStyles(theme),
      ...styles(theme, { ...customStyles }),
    }
  })
}

Solution

  • We can achieve this by making the key of the record returned by the passed styles function generic such that the information required to infer these properties is not lost.

    import { Theme } from '@mui/material'
    import { CSSObject } from 'tss-react'
    import { commonStyles } from '../commonStyles'
    import { makeStyles } from './helpers'
    
    export const getUseStyles = <
      RuleNames extends string,
      CustomStyles extends Record<string, any>,
    >(
      styles: (
        theme: Theme,
        customStyles?: CustomStyles,
      ) => Record<RuleNames, CSSObject>,
      customStyles?: CustomStyles,
    ) => {
      return makeStyles()((theme) => {
        return {
          ...commonStyles(theme),
          ...styles(theme, { ...customStyles } as CustomStyles),
        }
      })
    }
    
    

    enter image description here

    It's unclear what the purpose of customStyles is or how it affects the return values of the passed styles function. So that basically doesn't do anything type-wise here currently.