Material-ui: withStyles() 返回的组件中的 Typescript 类型错误

创建于 2017-09-28  ·  55评论  ·  资料来源: mui-org/material-ui

在打字稿中使用withStyles() hoc 时,尝试使用返回的组件时出现以下错误:

Type '{}' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<App> & Readonly<{ children?: ReactNode; }> & Reado...'.
  Type '{}' is not assignable to type 'Readonly<WithStyles<"main">>'.
    Property 'classes' is missing in type '{}'.
  • [x] 我已经搜索了这个存储库的问题,并相信这不是重复的。

似乎对类型定义的这种更改可能与此问题有关。

预期行为

鉴于下面的App组件代码,我应该能够像在 1.0.0-beta.10 中那样使用组件<App />而不会出现类型错误。

当前行为

鉴于下面的App组件代码,尝试使用<App />导致上述错误。

编码

import * as React from 'react';
import { withStyles } from 'material-ui/styles';

const styles = {
    main: {
        marginTop: 48,
        padding: 10,
    },
    foo: {
        margin: 0,
    },
};

interface Props {
    message: string;
};

type ClassNames = { classes: { [className in keyof typeof styles]: string } };

class App extends React.Component<Props & ClassNames> {
    render() {
        const { classes, message } = this.props;
        return (
            <div className={classes.main}>
                <div className={classes.foo} >
                    Hello World! {message}
                </div>
            </div>
        );
    }
}

export default withStyles(styles)(App);

语境

该代码在 1.0.0-beta.10 中运行良好,当我升级到 1.0.0-beta.12 时出现类型错误。

在提供的代码片段中,我使用了keyof typeof styles技巧,这样我就不需要两次定义类名列表(我非常不喜欢重复性)。 我还尝试了其他变体:

type ClassNames = WithStyles<keyof typeof styles>;

并以更常见的方式进行(如style.spec.tsx 中所示):

type ComponentClassNames = 'main' | 'foo';
type ClassNames = WithStyles<ComponentClassNames>;

我仍然遇到同样的错误。

似乎之前的类型定义会返回一个组件,其 props 类型为StyledComponentProps ,它有一个可选的classes属性。 新定义...

<P, C extends React.ComponentClass<P & StyledComponentProps<Names>>>(
    component: C
  ): C;

...返回与组件相同的类型C ,这意味着传递未标记为可选的ClassNames会传播到返回的组件。 我看到这里提到了Partial<> ,我认为这是一个难看的黑客。

您的环境

| 科技 | 版本 |
|--------------|---------|
| Material-UI | 1.0.0-beta.12 |
| 反应 | 15.6.1 |
| 浏览器 | 铬 61.0.3163.100 |

discussion typescript

最有用的评论

我用recompose解决了

例子

import { StyleRules, Theme, withStyles } from "material-ui/styles";
import * as React from "react";
import { compose } from "recompose";

interface IProps {
    classes?: any; // <-- add question mark
    text: string;
}

const styles = (theme: Theme): StyleRules => ({
    root: {

    },
});

@compose(
    withStyles(styles),
)
export class MyComponent extends React.Component<IProps> {
    render() {
        const { classes, text } = this.props;
        return (
            <div className={classes.root}>
                {text}
            </div>
        );
    }
}

所有55条评论

@cfilipov装饰组件类时应该使用StyledComponentProps而不是WithStyles ,如果在严格类型检查模式下,则需要使用非空断言运算符!来提取classes的字段。 这是允许使用withStyles作为类装饰器的妥协。 TypeScript 中的类装饰器受到它们的返回类型必须与参数类型匹配的限制。 鉴于此限制,只有一种选择是可能的:

  1. 不支持使用withStyles作为类装饰器
  2. 要求在构造装饰组件类型的元素时传递一个虚拟的classes道具(之前的妥协,可以说更烦人
  3. 要求在组件内部将classes视为可以为空,迫使您在访问其字段时使用!运算符(当前的妥协

我强烈建议,如果您的组件没有状态,则使用无状态功能组件,这将需要更少的类型注释并且类型更安全:

export default withStyles(styles)<Props>(({ classes, message }) => (
  <div className={classes.main}>
    <div className={classes.foo}>
      Hello World! {message}
    </div>
  </div>
));

我看到这里提到了 Partial<> 的使用,我认为这是一个难看的黑客。

如果您阅读我对该评论的跟进,您会发现不需要Partial<>

如果您阅读我对该评论的跟进,您会看到 Partial<> 不是必需的。

我看到您对Partial<> 。 使用StyledComponentProps基本上等同于同一件事(它在该定义中使用Partial<> )。 我对此的抱怨是现在必须使用!访问类名(如您所述)。 我认为传递一个虚拟的classes道具或要求使用!都是糟糕的妥协。

澄清一下,我想我在这里遇到的根本问题是选择将回归引入 hoc 以解决打字稿实验功能的限制。 我承认有一些偏见,因为我不关心装饰者,而其他人显然关心,但这里的权衡对我来说没有意义。

@cfilipovwithStyles类型的第一个重构是选择选项 (1),即使类和函数组件的类型完全正确,代价是使用withStyles作为类装饰器. 然后我得到反馈说使用装饰器语法是一个流行的请求,所以我切换到选项 (3)。 我很高兴重新考虑这个决定; 我也更喜欢类型安全,而不是在当前的半功能状态下支持装饰器。

是的,我理解支持这样一个受欢迎的请求的愿望。 我也使用装饰器,但我每次使用它们时都会遇到很多问题(在 mui 之外),所以我个人决定在它们准备好之前不使用它们。

听起来你和我一样担心,我没有更多要补充的,所以希望其他人可以在这个方向提供反馈来帮助影响它。

我从 beta.10 切换到 beta.13,看看是否有任何变化,是的,这是一个真正的问题。 把我的 2 美分扔在这里,对我来说,装饰器是实验性的。 他们显然可以在未来改变。 在那之前,我将完全支持 100% 准确的方式。 我宁愿有连贯的类型安全来破解我的类型以使其工作。

8550 看起来像是人们对此感到困惑的进一步证据,我们应该考虑不支持@withStyles()作为装饰器(在 TypeScript 中)。

如果我们使类型正确,这就是“装饰”类的样子:

type NonStyleProps = {
  text: string
};

const styles = {
  root: {
    backgroundColor: 'red'
  }
};

const DecoratedComponent = withStyles(styles)(
  class extends React.Component<NonStyleProps & WithStyles<'root'>> {
    render() {
      return (
        <div className={this.props.classes.root}>
          {this.props.text}
        </div>
      );
    }
  }
);

@pelotom由于这个问题,我还没有从 beta.10 开始。 我之前用 Redux 的 connect 方法对类的样式发表了评论。 我认为它相对容易和健壮。 在 #8059 中,第三条评论是我自己的类型。

@pelotom 非常感谢您在这个问题上对我们进行教育。 我是 TS 装饰器的大用户,但在那种情况下,我很高兴withStyles放弃它的装饰支持,以获得更好的类型安全。

我们应该考虑不支持 @withStyles() 作为装饰器(在 TypeScript 中)。

@pelotom我个人赞成这种改变。 @sebald你想在这里做什么?

这是一个简单的改变; 我继续并打开了一个 PR 以防你想使用它🙂

@pelotom如果我这样使用它们,

interface IStyles {
    // styles interface
}
interface IHeaderInfoStyles {
    classes: any;
}
interface IHeaderInfoProps {
    // properties resulting from dispatches
}
interface IHeaderInfoInjectedProps {
   // props injected from parent if any
}
interface IHeaderInfoDispatchProps {
    // dispatches
}
interface IHeaderInfoState {
    // your state for the class
}

type HeaderInfoProps = IHeaderInfoProps & IHeaderInfoInjectedProps & IHeaderInfoDispatchProps & IHeaderInfoStyles;

class HeaderInfo extends Component<HeaderInfoProps, IHeaderInfoState> {

export const HeaderInfo_container = withStyles<IHeaderInfoInjectedProps, IStyles>(styles)(
    connect<IHeaderInfoProps, IHeaderInfoDispatchProps, (IHeaderInfoInjectedProps & IHeaderInfoStyles)>(mapStateToProps, mapDispatchToProps)(HeaderInfo),
);

@marcusjwhelan withStyles不再需要 2 个类型参数,并且您不必为样式提供类型参数(可以从styles推断出)。 你应该能够写

withStyles(styles)<NonStyleProps>(...);

如果您提供mapStateToPropsmapDispatchToProps我可能会向您展示这对于您的示例会是什么样子。

tl;博士; 让我们做些改变,看看反弹是什么,我猜👷🏻


@oliviertassinari @pelotom ¯_(ツ)_/¯ 我不使用装饰器,所以就我个人而言,我真的不关心这个变化,因为我没有受到影响。 但似乎很多人确实关心这个“功能”。 这就是我们首先添加它的原因。 恕我直言,这里有优先权。

我对withStyles的变化感到非常满意,但是当您查看其他功能更多的库时,例如ramdarecompose ,类型并不那么严格,它们也不是超级类型安全的。 很多时候你必须传入一个泛型,它代表一个函数的返回值。 不漂亮,但它适用于 99.9% 的用户。

为什么我们不能带回对使用装饰器的人有用的旧类型? 因为它确实有两个泛型,所以我们可以将两种类型并排使用。

另外,我有点困惑人们对装饰器的问题是什么(关于“不工作”)。 毕竟像 Angular 和https://nestjs.com/这样的 Lib 大量使用它们。 在我们的例子中,人们只需在道具中添加WithStyles可以了。

@sebald

为什么我们不能带回对使用装饰器的人有用的旧类型? 因为它确实有两个泛型,所以我们可以将两种类型并排使用。

我不确定你是什么意思。 从来没有任何类型可以让人们轻松地使用装饰器。 第一个实现受到#8267 的影响,即您无法在不传递虚拟classes属性的情况下构造装饰组件的元素,例如<StyledComp classes={{} as any} /> 。 第二个(当前)实现存在相反的问题,即classes在组件类中被视为潜在的undefined 。 如果你想以当前的形式使用 TypeScript 装饰器,那是你唯一的两个选择; 选择你的毒药。

第三种方法是使用正确的类型,这样classes在类中定义但不需要作为道具传递。 要同时具​​备这两个条件,您需要放弃装饰器。

@pelotom是的,对不起。 你是对的。 真的不是我的日子...... 🤐 所以让我们合并吧!

@sebald

另外,我有点困惑人们对装饰器的问题是什么(关于“不工作”)。 毕竟像 Angular 和https://nestjs.com/这样的 Lib 大量使用它们。

我不确定它们是如何在 Angular 中使用的,但肯定有一些用例可以轻松使用装饰器; 基本上,如果装饰器不需要更改它所装饰的类的类型,它们就可以正常工作。 这不是我们这里的情况; withStyles需要改变它装饰的组件的类型。

@pelotom是的,没错。 只是突变是不好的。 实际上,TS 目前实现装饰器的方式甚至可能对 Angular 用户有好处,因为装饰器 AFAIK 与框架建立了契约,例如“将此类注册为组件”或“添加元数据,以便我可以在 DI 中使用它“......上帝甚至写到这个让我觉得🤢

@pelotom我拥有这些类型的原因是它为我的组件提供了类型安全。 目前,这些类型在组件方面没有类型安全性。 在我的例子injectedProps是由该组件工作所需的类型。 从react-redux连接的类型需要是来自mapStateToPropsProps和来自mapDispatchToProps 的DispatchProps类型

最后需要有injectedProps,以便我的父组件知道我需要注入它们,否则我的项目将无法编译。 (这就是我要的)。 这种变化会迁移回这种类型安全吗?

再次@marcusjwhelan ,如果您能提供在 beta 10 中编译的完整(但最少)示例,我可以向您展示如何迁移。 AFAIK 新版本应该比以前更具有表现力和更安全的类型。

@pelotom愚蠢的问题,有没有办法在新版本完成后得到通知?

@wcandillon在 Twitter 上关注我们。

@pelotom我确实在上面发布了一个例子......为什么你需要看到更多? 您可以假设属性是 a、b、c、d、e。 唯一的问题是注入的道具需要作为要求发出。

编辑

我想到了。

我进入这个讨论有点晚了,但我一直看到这里提到的类似错误,我还没有确定如何纠正它。 我正在使用[email protected][email protected]

const LoginForm = withStyles(styles)(
    class extends React.Component<WithStyles<'root' | 'button'>, ILoginFormState> {
    // ...
    }
);

render(
  <MuiThemeProvider theme={theme}>
    <LoginForm />
  </MuiThemeProvider>,
  document.getElementById('login-form')
);

我在这种特殊情况下收到的错误消息是:

Type '{}' is not assignable to type 'IntrinsicAttributes & WithStyles<"root" | "button"> & StyledComponentP...'.
  Type '{}' is not assignable to type 'WithStyles<"root" | "button" | "progress" | "textField">'.
    Property 'classes' is missing in type '{}'.
 not assignable to type 'WithStyles<"root" | "button" | "progress" | "textField">'.
    Property 'classes' is missing in type '{}'.

装饰组件类时,您应该使用 StyledComponentProps 而不是 WithStyles

@pelotom - 某处有这样的例子吗? 我在确定如何在 TypeScript 中设置有状态组件类的样式时遇到了很多麻烦。

@iamjem有点难以判断,因为您没有提供styles ,但看起来第一个问题是您在styles提到的类键比在WithStyles<...>提到的要多

const LoginForm = withStyles(styles)(
    class extends React.Component<WithStyles<keyof typeof styles>, ILoginFormState> {
    // ...
    }
);

它应该处理第一个问题。 那么看起来还有第二个问题,就是LoginForm的结果类型是

React.ComponentType<WithStyles<"root" | "button"> & StyledComponentProps<"root" | "button">>

这显然是不正确的; 看起来没有非样式道具会混淆类型系统。 您可以通过将{}作为类型参数传递来明确说明非样式道具是什么来帮助它:

const LoginForm = withStyles(styles)<{}>( // <-- note the type argument
    class extends React.Component<WithStyles<keyof typeof styles>, ILoginFormState> {
    // ...
    }
);

对不起,它太复杂了,我希望我知道一种更简单的方法来使这些东西工作!

成功了! 感谢@pelotom 的快速帮助。 我已经使用 React 很长时间了,但最近才开始使用 Material-ui,我想在我使用它的时候尝试一下 Typescript。 毋庸置疑,我发现在某些边缘情况下很难说出如何让 Typescript 满意。

我用recompose解决了

例子

import { StyleRules, Theme, withStyles } from "material-ui/styles";
import * as React from "react";
import { compose } from "recompose";

interface IProps {
    classes?: any; // <-- add question mark
    text: string;
}

const styles = (theme: Theme): StyleRules => ({
    root: {

    },
});

@compose(
    withStyles(styles),
)
export class MyComponent extends React.Component<IProps> {
    render() {
        const { classes, text } = this.props;
        return (
            <div className={classes.root}>
                {text}
            </div>
        );
    }
}

我正在与这个问题(和#8704)作斗争,过去几天没有明确的结果。 然后我接受了@pelotom的建议:

你应该使用StyledComponentProps而不是WithStyles

并在 GitHub 上搜索类似的方法来解决这个问题。 我找到了一个工作示例😂。 不过,这是一个很好的方法,它确实解决了我的问题 - 将容器和组件分开,TypeScript 是一个快乐的饼干:这里提到的例子注意:在我的情况下,组件映射在一个单独的容器文件中,但这个想法是相同的。)。

如果有人认为这是一个糟糕的解决方案,我愿意接受任何更改和想法。 现在,我很高兴我的代码不再抱怨。

type Styles = 'foo';
const styles: StyleRulesCallback<Styles> = (theme: Theme) => ({
    foo: {
        position: 'relative',
    }
});

interface Props {
  something: string;
}

class Sidebar extends React.Component<Props & WithStyles<Styles>> {
    render() {
        const { classes, something } = this.props;

        return (
                    <div className={classes.foo}>{something}</div>
        );
    }
}

export default withStyles(styles)<Props>(Sidebar);

我不想创建一个新问题,但我已经尝试了我在文档、示例和传递的问题中看到的任何内容,即使是重构,但是当我向它添加一些属性时,我无法使我的组件工作。
我找到的资源大多是旧版本的 TS、MUI 甚至 React。

这是我的组件:

import React from 'react';
import AppBar from 'material-ui/AppBar';
import { withStyles, WithStyles, StyleRulesCallback } from 'material-ui/styles';

const styles: StyleRulesCallback<'positionFixed'> = () => ({
  positionFixed: {
    top: 'auto',
    bottom: 0,
  },
});

const decorate = withStyles(styles);

interface Props {
   someProp: string;
};

export const BottomNav = decorate<Props>(
  class extends React.Component<Props & WithStyles<'positionFixed'>, {}> {
    render() {
      return (
        <AppBar />
      );
    }
  }
);

export default BottomNav;

错误是:

TS2322: Type '{}' is not assignable to type 'IntrinsicAttributes & Props & StyledComponentProps<"positionFixed"> & { children?: ReactNode; }'.
  Type '{}' is not assignable to type 'Props'.
    Property 'someProp' is missing in type '{}'.

我是 TS 的初学者,但我发现文档页面示例非常混乱和/或不完整。

如果你们有任何想法,谢谢;-)

@otroboe您是否

<BottomNav />

如果是这样,问题是您需要提供someProp道具(根据您对Props定义是必需的):

<BottomNav someProp="foo" />

为我感到羞耻……哦,为我感到羞耻。
我太专注于 TS 集成,我忘了环顾四周并退后几步。

非常感谢@pelotom :smile:

@otroboe还要删除字符串重复...

type Styles = 'positionFixed';

但希望那个更容易...

是的,我也这样做了,谢谢:+1:

我刚刚遇到了同样的问题,但结果证明只有当我在与我的类或函数相同的文件中初始化样式对象时才会发生这种情况。 或者,如果我从另一个文件导入样式,则不会出现此错误。

任何线索为什么会发生这种情况?

@nishmeht7你能发布一个独立的片段吗?

@pelotom我刚刚制作了一个,它在我的沙箱环境中运行良好。 我目前正在开发一个大型应用程序,并且仍在使用 mui 版本 1.2.2,而我的沙箱 env 版本是最新版本。 所以我猜一旦我升级了版本,我将无法重现我的错误。

我遵循了https://material-ui.com/demos/selects/中的基本表单示例,但有人抱怨theme没有root (使用最新的打字稿和材料- ui),并且没有类被应用于form元素。 我尝试按照上面的讨论进行操作,但似乎没有定论。 实际上,继承的类列表缺少为form生成的类名。 如果我手动添加了生成的类名(在开发工具检查元素中的 withStyles 中找到console.log(theme) ,一切都很好,所以显然类是正确生成的。没有通过withStyles传递给form元素虽然很混乱。

所以我现在已经恢复到样式,直到它被排序:

<form style = {{display:'flex',flexWrap:'wrap'}} autoComplete="off">

@HenrikBechmann您是否尝试过遵循https://material-ui.com/guides/typescript/

谢谢@lookfirst! 我看了(虽然不是第一次:-))那个文档,并使用了

export default withStyles({
  root: {
    display: 'flex',
    flexWrap: 'wrap',
  },
})(BaseForm)

(传递对象而不是函数)

...这既避免了打字稿错误,又启用了生成类的注入。

希望那里的其他技巧将有助于更复杂的结构。

我还确认styles函数的更复杂结构有效(将生成的className注入form ):

import React from 'react'

import { withStyles, createStyles, Theme } from '@material-ui/core/styles'

/*
    patterned after first demo https://material-ui.com/demos/selects/ for 3.03
    use Typsecript fixes from here: https://material-ui.com/guides/typescript/
*/

const styles = (theme:Theme) => createStyles({
  root: {
    display: 'flex',
    flexWrap: 'wrap',
  },
})

class BaseForm extends React.Component<any,any> {

    render() {
        const { classes } = this.props

        return (
            <form className = {classes.root} autoComplete="off">
                {this.props.children}
            </form>
        )
    }
}

export default withStyles(styles)(BaseForm)

编辑: @eps1lon指出,使用WithStyles是不必要的!

我使用ReturnType<T>为我生成ClassKey取得了一些成功:

import * as React from 'react';

import withStyles, {
  StyledComponentProps, 
  StyleRulesCallback,
} from '@material-ui/core/styles/withStyles';

import { Theme } from '@material-ui/core/styles/createMuiTheme';

const overrideStyles = (theme: Theme) => ({
  root: {
    display: 'flex',
    flexDirection: 'column',
  },
});

type Props = StyledComponentProps<keyof ReturnType<typeof overrideStyles>>;

class MyComponent extends React.PureComponent<Props> {
  render() {
    return <div className={this.props.classes.root}></div>;
  }
}

export default withStyles(overrideStyles as StyleRulesCallback, {withTheme: true})(MyComponent);

使用keyof ReturnType<typeof styleOverrides>作为StyledComponentProps ClassKey将从overrideStyles返回的对象中获取键,并使您不必手动保留这些键的列表. 如果我没有在withStyles调用中强制转换overrideStyles as StyleRulesCallback ,我注意到的唯一故障是类型错误。 我不是 100% 确定为什么。 我认为withStyles出于某种原因不了解overrideStyles是什么。

为了澄清这个相当复杂的类型, typeof styleOverrides解析为返回样式对象的函数。 ReturnType<T>将为您提供样式对象本身。 keyof将从样式对象中获取键。

@chrislambe您应该打字稿指南。 您不应该需要使用ReturnType等。 createStylesWithStyles应该足以作为助手。

@eps1lon哦,嘿,很酷! 谢谢!

fwiw 我越来越喜欢 createStyles/withStyles 对,因为我使用它们。 促进整洁的代码,处理我所有的样式/打字稿问题,如果我想要本地条件 css,我只需要创建本地样式属性,这当然优先于类。

好的!!

按照@material-ui/ [email protected]的打字稿指南,我得到了Test does not have required attribute classes

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

const styles = (theme: Theme) => createStyles({
  root: {
    color: theme.palette.action.active
  },
})

interface Props extends WithStyles<typeof styles> {
  asd: boolean
}

class TestComponent extends React.Component<Props> {

  render() {
    const { classes } = this.props

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

const Test = withStyles(styles)(TestComponent)

const a = () => <Test asd={true}/>

@aaronlifton2
请遵循使用 WithStyles 增强道具

@valoricDe你的问题解决了吗?

@TrejGun我刚刚检查过。 使用功能组件和@material-ui/ [email protected]我没有这个问题

我真的不明白。
遵循此处的文档: https: //material-ui.com/guides/typescript/#augmenting -your-props-using-withstyles
似乎只是导致了这个原始问题的问题。 当你在某处使用组件时,打字稿要求你_pass_classes 属性作为道具,而不是意识到它会被withStyles _injected_。

我已经阅读这些问题几个小时了,但我并没有真正理解。 在这一点上,任何帮助都会非常好。

关于上面的这个建议

@cfilipov装饰组件类时应该使用StyledComponentProps而不是WithStyles ,如果在严格类型检查模式下,则需要使用非空断言运算符!来提取classes的字段。 这是允许使用withStyles作为类装饰器的妥协。 TypeScript 中的类装饰器受到它们的返回类型必须与参数类型匹配的限制。 鉴于此限制,只有一种选择是可能的:

  1. 不支持使用withStyles作为类装饰器
  2. 要求在构造装饰组件类型的元素时传递一个虚拟的classes道具(之前的妥协,可以说更烦人
  3. 要求在组件内部将classes视为可以为空,迫使您在访问其字段时使用!运算符(当前的妥协

我强烈建议,如果您的组件没有状态,则使用无状态功能组件,这将需要更少的类型注释并且类型更安全:

export default withStyles(styles)<Props>(({ classes, message }) => (
  <div className={classes.main}>
    <div className={classes.foo}>
      Hello World! {message}
    </div>
  </div>
));

我如何知道如何使用StyledComponentProps ? 看来我只是传递样式对象中定义的键的字符串。

但是文档告诉我们做一些根本行不通的事情? 我错过了什么? 我想使用https://material-ui.com/guides/typescript/#augmenting -your-props-using-withstyles ...

这可能吗?

@valoricDe ,你是怎么做没有那个问题的功能组件的

@TrejGun我刚刚检查过。 使用功能组件和@material-ui/ [email protected]我没有这个问题

我正在尝试这样的事情:

```import React, { ChangeEvent, Component, Dispatch } from "react";
从“prop-types”导入 PropTypes;
从“react-redux”导入{连接};
import { Grid, FormControlLabel, Theme, createStyles, withStyles, Radio, WithStyles } from "@material-ui/core";
从“./Amount”导入金额;
从“../../store/actions/selectPaymentAmountActions”导入 { onPastDueFormFieldChange };

const 样式 = (主题: 主题) =>
创建样式({
数量: {
alignSelf: "中心",
},
});

接口 OwnProps 扩展了 WithStyles{}

接口状态道具{
过期?:数字;
PastDueOrTotalOrOther:字符串;
}

接口 DispatchProps {
onPastDueFormFieldChange: OnPastDueFormFieldChange;
}

类型道具 = StateProps & DispatchProps & OwnProps;

const PastDueFormField = withStyles(styles)(
({ classes, pastDue, pastDueOrTotalOrOther, onPastDueFormFieldChange }: 道具) => (
价值=“过期”
已检查={pastDueOrTotalOrOther === "pastDue"}
onChange={onPastDueFormFieldChange}
标签=“逾期:”
控制={ }
/>




),
);

const mapStateToProps = (state: RootState): StateProps => ({
过期:state.customerData.balanceDue.pastDue,
PastDueOrTotalOrOther:state.customerPaymentsForm.pastDueTotalOrOther,
});

导出默认连接(
mapStateToProps,
{ onPastDueFormFieldChange },
)(PastDueFormField);

When I use this component I have this error:
```import PastDueFormField
Property 'classes' is missing in type '{}' but required in type 'Readonly<PropsWithChildren<Pick<Pick<Props, "pastDue" | "pastDueOrTotalOrOther" | "onPastDueFormFieldChange"> & StyledComponentProps<"amount">, "classes" | "innerRef"> & OwnProps>>'

@yehudamakarov 首先尝试在没有react-redux情况下编写代码,然后在一切正常时添加connect 。 当注入什么 prop 时,很难获得一个好的概览。

遇到这些问题我会

  1. 首先输入我的组件道具
  2. 检查是否一切都按预期进行,即获得missing props
  3. 临时申请
  4. 看看打字稿是否识别出每个注入的道具
  5. 重复 3,直到应用所有 hoc。

它促进更清洁的代码。 尤其是在操作顺序方面。 您目前混合withStylesconnect而没有分离关注点。

非常感谢塞巴斯蒂安。
我通过简单地不传递通用参数来解决我的问题。 我取出了<StateProps ...>块。

我认为这些通用参数与我扩展 WithStyles<> 的 OwnProps 接口混淆。

由于我将所有内容都传递给组件,因此我从 Props 获得的类型检查就足够了。 不知道为什么 id 需要 connect<> 泛型。

谢谢!

如果我们使类型正确,这就是“装饰”类的样子:

type NonStyleProps = {
  text: string
};

const styles = {
  root: {
    backgroundColor: 'red'
  }
};

const DecoratedComponent = withStyles(styles)(
  class extends React.Component<NonStyleProps & WithStyles<'root'>> {
    render() {
      return (
        <div className={this.props.classes.root}>
          {this.props.text}
        </div>
      );
    }
  }
);

以及如何在其中添加主题(useTheme()),例如:

const decorate = withStyles((theme: Theme) => ({
  root: {
    display: "flex"
  },
  appBar: {
    zIndex: theme.zIndex.drawer + 1,
    transition: theme.transitions.create(["width", "margin"], {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen
    })
  }
})
此页面是否有帮助?
0 / 5 - 0 等级