score:4

Accepted answer

what this means is that the declared type of the @withstyles decorator:

export default function withstyles<p = {}, classnames = {}>(
  style: stylerules | stylerulescallback,
  options?: withstylesoptions
): (
  component: react.componenttype<p & { classes: classnames; theme?: theme }>
) => react.componentclass<p & styledcomponentprops<classnames>>;

doesn't actually meet the contract that typescript needs for class decorators, which is something more like:

declare function classdecorator(...args: any[]): <c> (c: c) => c;

the contract is pretty strict: it requires that the function output be a subtype of the input. this has led people to have problems before.


if everything is working fine at runtime and you just want to silence the type checker, there's always good old any:

@(withstyles as any)(styles) // no error now
class mycomponent extends react.component<any, any> {
    manager: any;
    ...
}

or, you could go ahead and try to re-declare the type of withstyles() to be more friendly to decorators:

import { styledcomponentprops } from 'material-ui';
import { theme } from 'material-ui/styles/createmuitheme';
import { stylerules, stylerulescallback, withstylesoptions } from 'material-ui/styles/withstyles';
import { withstyles } from 'material-ui/styles'
declare module 'material-ui/styles' {
  export function withstyles(
    style: stylerules | stylerulescallback,
    options?: withstylesoptions
  ): <c extends react.componenttype<p & { classes: classnames; theme?: theme }>, p = {}, classnames = {}> (
      component: c
    ) => c & react.componentclass<p & styledcomponentprops<classnames>>;

}
@withstyles(styles) // no error now
class mycomponent extends react.component<any, any> {
  manager: any;
}

now everything works because i ensure that the returned value is a subtype of the mycomponent constructor. it's a lot of someone else's code to fix in your own project; i'd probably just use the any solution myself.

whether someone wants to contact the material ui folks and suggest updating the definition is up to them. i don't consider myself knowledgeable enough on react et al. to understand if my altered declaration is appropriate.

anyway, hope that helps; good luck!

score:1

i wasn't able to use @jcalz's type definition since it conflicts with the existing one, so i made a wrapper function.

having classes be required on withstyles also makes it a pain to use decorated components, so i make it optional instead.

// withstyles.ts

import { theme } from 'material-ui/styles';
import _withstyles, {
  classnamemap,
  styledcomponentprops,
  stylerules,
  stylerulescallback,
  withstylesoptions,
} from 'material-ui/styles/withstyles';

export interface withstyles<classkey extends string = string> {
  classes?: classnamemap<classkey>;
  theme?: theme;
}

// we need to fix the withstyles definition and we want to make withstyles.classes optional,
// so we make our own.
export const withstyles = <classkey extends string>(
  style: stylerules<classkey> | stylerulescallback<classkey>,
  options?: withstylesoptions
) => <c extends react.componenttype<p & withstyles<classkey>>, p = {}>(component: c) => {
  return (_withstyles as any)(style, options)(component) as c & react.componenttype<p & styledcomponentprops<classkey>>;
};

to use it just import the new withstyles.ts instead of the material-ui one.

import { withstyles, withstyles } from './withstyles';

@withstyles(styles)
export class myclass extends react.component<myclassprops> {
  render() {
    // classes will always exist so use `!`.
    const classes = this.props.classes!;

    return (
      <div classname={classes.root} />
    );
  }
}

Related Query

More Query from same tag