How to type the use of Material-UI's `withStyles` decorator in the example?

巧了我就是萌 提交于 2020-01-04 03:52:06

问题


I'm trying to figure out how to annotate the types of the following styles (I converted from plain JavaScript to TypeScript and am adding type annotations):

import * as React from 'react'
import { withStyles } from '@material-ui/core'

@withStyles(styles) // TYPE ERROR HERE
export default class App extends React.Component<{}, {}> {
    render(): JSX.Element {
        return (
            <div className="some-class"> Hello </div>
        )
    }
}

function styles() {
    return {
        // assume I need to use global styles, my actual project is more
        // complex and for some reasons I need to use global styles
        '@global': {
            '.some-class': {
                overflowX: 'hidden'
            },
        },
    }
}

How do we type this?

At first, it gives me an error like:

        Types of property 'overflowX' are incompatible.
          Type 'string' is not assignable to type '"scroll" | "hidden" | "visible" | "auto" | "clip" | "-moz-initial" | "inherit" | "initial" | "revert" | "unset" | undefined'.

So I changed it to the following which uses createStyles:

import * as React from 'react'
import { withStyles, createStyles } from '@material-ui/core'

@withStyles(styles) // TYPE ERROR HERE
export default class App extends React.Component<{}, {}> {
    render(): JSX.Element {
        return (
            <div className="some-class"> Hello </div>
        )
    }
}

function styles() {
    return createStyles({
        // assume I need to use global styles, my actual project is more
        // complex and for some reasons I need to use global styles
        '@global': {
            '.some-class': {
                overflowX: 'hidden'
            },
        },
    })
}

And now I get this error:

tmp.tsx:5:1 - error TS1238: Unable to resolve signature of class decorator when called as an expression.
  Type 'ComponentClass<Pick<{}, never> & StyledComponentProps<"@global">, any>' is not assignable to type 'void | typeof App'.
    Type 'ComponentClass<Pick<{}, never> & StyledComponentProps<"@global">, any>' is not assignable to type 'typeof App'.
      Type 'Component<Pick<{}, never> & StyledComponentProps<"@global">, any, any>' is not assignable to type 'App'.
        Types of property 'render' are incompatible.
          Type '() => ReactNode' is not assignable to type '() => Element'.
            Type 'ReactNode' is not assignable to type 'Element'.
              Type 'undefined' is not assignable to type 'Element'.

5 @withStyles(styles) // TYPE ERROR HERE
  ~~~~~~~~~~~~~~~~~~~

In my actual, more-complicated code, the error is similar, about not being able to match the Component type:

App.tsx:44:1 - error TS1238: Unable to resolve signature of class decorator when called as an expression.
  Type 'ComponentClass<Pick<AppProps, never> & StyledComponentProps<"@global">, any>' is not assignable to type 'void | typeof App'.
    Type 'ComponentClass<Pick<AppProps, never> & StyledComponentProps<"@global">, any>' is not assignable to type 'typeof App'.
      Type 'Component<Pick<AppProps, never> & StyledComponentProps<"@global">, any, any>' is not assignable to type 'App'.
        Property 'makeOnStatusWindowClick' is missing in type 'Component<Pick<AppProps, never> & StyledComponentProps<"@global">, any, any>'.

44 @withStyles(styles)
   ~~~~~~~~~~~~~~~~~~~

where makeOnStatusWindowClick is the very first method defined in my component class.


回答1:


The Material UI docs that Daniel linked to say

Unfortunately due to a current limitation of TypeScript decorators, withStyles(styles) can't be used as a decorator in TypeScript.

so I was able to get it working by doing two things:

  • use createStyles on the return object of my styles function (and don't use an explicit return type definition on the function so that it uses the one generated by createStyles)
  • Use withStyles as not a decorator
  • Use WithStyles for your props, using the auto-detected type of your styles

The code looks like this:

import * as React from 'react'
import { withStyles, WithStyles, createStyles } from '@material-ui/core'

interface Props extends WithStyles<typeof styles> {}

class App extends React.Component<Props, {}> {
    render(): JSX.Element {
        return (
            <div className="some-class"> Hello </div>
        )
    }
}

export default withStyles(styles)(App)

function styles() /*: do not put a return type here */ {
    return createStyles({
        // assume I need to use global styles, my actual project is more
        // complex and for some reasons I need to use global styles
        '@global': {
            '.some-class': {
                overflowX: 'hidden'
            },
        },
    })
}



回答2:


Fortunately they have an extensive documentation on typescript here https://material-ui.com/guides/typescript/

Also you are not mentioning the error you are getting, so it's tricky to know what's wrong

Probably your props type is missing classes field



来源:https://stackoverflow.com/questions/53138167/how-to-type-the-use-of-material-uis-withstyles-decorator-in-the-example

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!