javascript - 将类型定义添加到将 props 注入(inject)组件的 HOC

标签 javascript reactjs typescript

我有一个以下列方式(无类型)实现的“高阶组件”。

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 的 prop 传递给组件。实际上,它将按如下方式使用(在此范围内称为 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 中完成?

最佳答案

主题.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())}
        />
      );
    }
  };
}

关于javascript - 将类型定义添加到将 props 注入(inject)组件的 HOC,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47701205/

相关文章:

javascript - 如何获取单选的数据价格 - JavaScript

reactjs - 为什么按钮只有在第二次单击后才起作用? ( react )

css - 如何使其父 div 的 NextJS Image 组件的高度和宽度为 100%?

javascript - ng-model 不绑定(bind)在 ng-repeat 中,而其他所有东西都绑定(bind)

javascript - jQuery Each Loop - 显示单个项目

javascript - 在 HTML 中制作 onclick 函数来执行 2 个函数

node.js - 全局设置 chai 配置(所有测试一次)

javascript - Axios 'put' 请求将数组作为空值传递

visual-studio-2013 - 在 vs 2013 中使用 Jasmine 测试 typescript

javascript - 使用管道和订阅时我的加载 Controller 放在哪里?