我试图在TypeScript(2.8)中的React文档(React 16.3)中实现示例Consuming Context with a HOC并且失败了。作为参考,来自React手册的代码:
const ThemeContext = React.createContext('light');
// This function takes a component...
export function withTheme(Component) {
// ...and returns another component...
return function ThemedComponent(props) {
// ... and renders the wrapped component with the context theme!
// Notice that we pass through any additional props as well
return (
<ThemeContext.Consumer>
{theme => <Component {...props} theme={theme} />}
</ThemeContext.Consumer>
);
};
}
我能想出的最好的结果:
export interface ThemeAwareProps {
theme: string;
}
const ThemeContext = React.createContext('light');
export function withTheme<P extends ThemeAwareProps, S>(Component: new() => React.Component<P, S>) {
return function ThemedComponent(props: P) {
return (
<ThemeContext.Consumer>
{theme => <Component {...props} theme={theme} />}
</ThemeContext.Consumer>
);
};
}
class App extends React.Component {
public render() {
return (
<ThemeContext.Provider value={'dark'}>
<ThemedButton/>
</ThemeContext.Provider>
);
}
}
ThemedButton.tsx:
interface ThemedButtonProps extends ThemeAwareProps {
}
interface ThemedButtonState{
}
class ThemedButton extends React.Component<ThemedButtonProps, ThemedButtonState> {
constructor(props: ThemedButtonProps) {
super(props);
}
public render() {
return (
<button className={this.props.theme}/>
)
}
}
export default withTheme(ThemedButton);
问题是最后一行(export default withTheme(ThemedButton)
)。 TypeScript编译器抱怨
类型
typeof ThemedButton
的参数不能分配给new () => Component<ThemedButtonProps, ThemedButtonState, any>
类型的参数。
我错过了什么?
答案 0 :(得分:12)
你在大多数情况下做得对,只是缺少一些东西:
对于Component
,请使用React.ComponentType<Props>
,它正确接受类组件和功能组件。我认为单独使用new () => ...
无法在这里工作,因为签名并不完全匹配。
要在使用道具时从ThemedButton
中排除道具,您必须使用一些神奇的语法:
function ThemedComponent(props: Pick<P, Exclude<keyof P, keyof ThemeAwareProps>>)
以下是这样做的:
Exclude<keyof P, keyof ThemeAwareProps>
表示&#34;获取P
的密钥,然后带走ThemeAwareProps
&#34; Pick<P, ...>
然后说,&#34;来自P
,返回仅包含这些属性的对象类型&#34; 组合这些组合为我们提供了一个组件,可以接受ThemedButton
所做的所有道具,减去theme
道具,这样我们就可以<ThemedButton />
毫无错误地执行。{/ p>
这是完整的HOC:
function withTheme<P extends ThemeAwareProps>(Component: React.ComponentType<P>) {
return function ThemedComponent(props: Pick<P, Exclude<keyof P, keyof ThemeAwareProps>>) {
return (
<ThemeContext.Consumer>
{(theme) => <Component {...props} theme={theme} />}
</ThemeContext.Consumer>
)
}
}
And finally, a good blog post on the subject, from which I gleamed most of this information from.如果您愿意,还可以使用Pick<...>
类型缩短Omit
内容。
编辑:The behavior of rest/spread has changed in 3.2和this bug came up as an unfortunate side effect,导致props
的类型在与其他道具合并时被删除。 A currently working workaround is to cast props
as P
:
return (
<ThemeContext.Consumer>
{(theme) => <Component {...props as P} theme={theme} />}
</ThemeContext.Consumer>
)