Reactjs 具有高阶函数的泛型

Reactjs 具有高阶函数的泛型,reactjs,typescript,rxjs,typescript-generics,Reactjs,Typescript,Rxjs,Typescript Generics,我想创建一个函数,为我现有的React 组件。返回值是传入函数组件的自定义类扩展 换言之: 我的高阶函数with observeStream()的返回值-它返回另一个 函数-获取现有的React组件(具有类型化的props)并返回新组件的构造函数 最终应该渲染到DOM。因为我只是用 订阅RxJS两个组件将共享相同的道具 类型系统应: 抱怨物业错配 我怎样才能做到这一点——谁能给我展示“泛型”的魔力?这可能吗 type Props = Triggers & InitialState;

我想创建一个函数,为我现有的
React
组件。返回值是传入函数组件的自定义类扩展

换言之:

我的高阶函数
with observeStream()
的返回值-它返回另一个 函数-获取现有的
React
组件(具有类型化的props)并返回新组件的构造函数 最终应该渲染到
DOM
。因为我只是用 订阅
RxJS
两个组件将共享相同的道具

类型系统应:

  • 抱怨物业错配
我怎样才能做到这一点——谁能给我展示“泛型”的魔力?这可能吗

type Props = Triggers & InitialState;

function App(props: Props) {
  return <button
  onClick={(event) => {
    props.onClick(event);
  }}
  >{props.text} (state: {props.counterX})</button>;
}

// still all good here:
const appInstance = App({...triggers, text: "init", counterX: -1});

const WrappedApp = withObservableStream(
  interval(5000).pipe(
    map((o) => ({counterX: o})),
  ),
  {...triggers},
  {
    // counterX: -1,
    text: "XXX",
  },
)(App);
// type sytem should complain meaningful here:
// 2nd & 3rd parameter of observableStream() should match the constructor signature of App (type Props)
// for both new WrappedApp(...) and render(<WrappedApp...)
type Props=触发器和初始状态;
功能应用程序(道具:道具){
返回{
道具。onClick(事件);
}}
>{props.text}(状态:{props.counterX});
}
//这里仍然很好:
const-appInstance=App({…触发器,文本:“init”,计数器x:-1});
const WrappedApp=带有ObservableStream(
间隔(5000)。管道(
map((o)=>({counterX:o})),
),
{…触发器},
{
//计数器X:-1,
正文:“XXX”,
},
)(App);
//此处的类型系统应为:
//ObservateStream()的第2和第3个参数应与应用程序的构造函数签名匹配(类型Props)

//对于新的WrappedApp(…)和render(),我修改了代码以添加所需的类型限制。 基本上,您需要将泛型类型添加到
的返回函数withObservableStream

使用ObserviceStream.tsx
从“React”导入React;
从“rxjs”导入可观察的;

导出默认值太棒了,看起来很有希望!你有没有建议我如何将
WrappedApp
的实例传递到
render()
const-appInstance=new-WrappedApp(…);render(appInstance,…);
请直接将相关信息放入答案中;外部链接会随着时间的推移而腐烂。请参阅“始终引用重要链接中最相关的部分,以防目标站点无法访问或永久脱机”。@YannicHamann我添加了一个示例,说明如何将其传递给渲染函数。
import React from "react";
import Observable from "rxjs";

export default <T extends Observable.Observable<any>, U, V>(observable: T, triggers: U, initialState: V) => {
  type cState = U & V;
  return function(Component: React.ComponentType<cState>) {

    return class extends React.Component<cState, V> {
      private subscription: any;

      constructor(props: cState) {
        console.log("got props", props);
        super(props);

        this.state = {
          ...initialState,
        };
        console.log(this.state);
      }

      public componentDidMount() {
        console.log("Subscribing...");
        this.subscription = observable.subscribe((newState) => {
          console.log("setting a new state...", newState);
          this.setState({ ...newState });
          console.log("state: ", this.state);
        });
      }

      public componentWillUnmount() {
        console.log("Unsubscribing...");
        this.subscription.unsubscribe();
      }


      public render() {
        return (
          <Component {...this.props} {...this.state} {...triggers} />
        );
      }
    }
  };
};
import React from "react";
import { render } from "react-dom";
import { interval } from "rxjs";
import { map } from "rxjs/operators";
import withObservableStream from "./withObservableStream";

type Triggers = {
  onClick(event: React.MouseEvent<HTMLButtonElement>): void,
};

type InitialState = {
  text: string,
  counterX: number,
};

type Props = Triggers & InitialState;

export function App(props: Props) {
  return <button
  onClick={(event) => {
    props.onClick(event);
  }}
  >{props.text} (state: {props.counterX})</button>;
}

const triggers: Triggers = { onClick: () => console.log("clicked!!!") };

const appInstance = App({...triggers, text: "init", counterX: -1});
render(appInstance, document.getElementById("root1"));

const WrappedApp = withObservableStream(
  interval(5000).pipe(
    map((o) => ({counterX: o})),
  ),
  {...triggers},
  {
    counterX: -1,
    text: "XXX",
  },
)(App);

const appInstance2 = new WrappedApp({...triggers, counterX: -1, text: "23"});

render(<WrappedApp {...triggers} counterX={-1} text="23"/>,  document.getElementById("root1"))
document.getElementById("root2"));