我有一个"更高阶的组件"这是以下列方式实现的(没有类型)。
const Themeable = (mapThemeToProps) => {
return (WrappedComponent) => {
const themedComponent = (props, { theme: appTheme }) => {
return <WrappedComponent
{...props}
theme={merge(
{},
defaultTheme,
appTheme,
mapThemeToProps(merge(defaultTheme, appTheme))
)}
>
}
themedComponent.contextTypes = { theme: PropTypes.object };
return themedComponent;
}
}
总结它的作用,它需要一个mapThemeToProps
函数。这将收到通过合并defaultTheme
(由我的库提供)和appTheme
(由ThemeProvider
组件通过上下文提供)创建的主题参数。然后,它将创建一个扩展的Theme
,并将其作为名为theme
的道具传递给组件。在实践中,它将按如下方式使用(在此范围内称为Themeable
):
const mapThemeToProps = (theme) => ({
background: theme.palette.dark,
color: theme.text.light,
});
function Greeting({ theme: { background, color } }) {
return (
<div style={{ background, color }}>
Hello World!
<div>
)
}
export default Themeable(mapThemeToProps)(Greeting);
我很难为这个功能开发正确的输入法。 I found this pattern is very similar to something along the lines of connect
from react-redux
so have been working from their typings作为我的出发点。无论如何,我有点失落,这基本上就是我所在的地方:
import { Theme } from 'types/Theme';
interface ThemeableComponentEnhancer {
<P>(component: React.ComponentType<P>): React.ComponentClass<Pick<P, "theme"> & { theme: Theme }> & { WrappedComponent: React.Component<P>}
}
export interface Themeable {
// calling it with no parameters returns a basic theme.
(): Theme;
// calling it with a function
<TTheme = {}>(mapThemeToProps: MapThemeToPropsParam<TTheme>): ComponentEnhancer<{ theme: TTheme }>;
}
interface MapThemeToProps<TTheme> {
(theme: TTheme): TTheme;
}
interface MapThemeToPropsFactory<TTheme> {
(theme: Theme): MapThemeToProps<TTheme>;
}
type MapThemeToPropsParam<TTheme> = MapStateToPropsFactory<TTheme>
我无法理解这一点。如何在TypeScript中完成?
答案 0 :(得分:5)
Theme.ts
export interface Theme {
palette: {
primary: string;
secondary: string;
};
}
export const theme: Theme = {
palette: {
primary: 'red',
secondary: 'yellow'
}
};
Rect
Theme
组件示例
import * as React from 'react';
import { Theme } from '../theme/Theme';
import withTheme, { MapThemeToProps } from '../theme/withTheme';
export interface RectThemeProps {
titleColor?: string;
bodyColor?: string;
}
export interface RectProps extends RectThemeProps {
content?: string;
}
export class Rect extends React.Component<RectProps> {
render() {
const {titleColor, bodyColor, content} = this.props;
return <div>{content && content}</div>;
}
}
const mapThemeToProps: MapThemeToProps<
RectThemeProps,
Theme
> = (theme) => {
return {
titleColor: theme.palette.primary,
bodyColor: theme.palette.secondary
};
};
export default withTheme(mapThemeToProps)(Rect);
withTheme.ts
import * as React from 'react';
const ID = '__context_id__';
export interface MapThemeToProps<M, T> {
(theme: T): M;
}
export interface withTheme {
<M, T>(mapThemeToProps: MapThemeToProps<M, T>):
(c: React.ComponentType<M>) => React.ComponentType<M>;
}
export default <M, T>(
mapThemeToProps: MapThemeToProps<M, T>
) => (Component: React.ComponentType<M>) => {
return class extends React.Component<M> {
render() {
const theme = this.context[ID];
return (
<Component
{...this.props}
{...mapThemeToProps(theme.getTheme())}
/>
);
}
};
}