Я пытаюсь написать функцию более высокого порядка для React в машинописном шрифте, которая: (1) требует определенных свойств обертываемого компонента (2) позволяет устанавливать свойства обернутых компонентов в обертке (3) имеет свойстваспецифично для оболочки
У меня в основном все работает, но когда я иду, чтобы установить свойства по умолчанию для анонимного класса, который оборачивает мой компонент, я получаю ошибку из машинописного текста, которую мне не удалось разрешить.
Я получаю ошибку:
src/withContainer.tsx:33:3 - error TS2322: Type 'typeof (Anonymous class)' is not assignable to type 'ComponentClass<P & ContainerProps, any>'.
Types of property 'defaultProps' are incompatible.
Type '{ loading: Element; }' is not assignable to type 'Partial<P & ContainerProps>'.
33 return class extends React.Component<P & ContainerProps, ContainerState> {
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
34 // Why does typescript say this is an error?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
...
80 }
~~~~~
81 };
~~~~
Вот пример того, что я пытаюсь сделать:
import * as React from "react";
/**
* Properties specific to the container component.
*/
export interface ContainerProps {
/* eslint-disable @typescript-eslint/no-explicit-any */
loading: React.ReactElement<any>;
}
export interface ContainerState {
data: {};
initialized: boolean;
}
/**
* Components being wrapped need a putData function on them.
*/
export interface PuttableProps {
/**
* Put data into state on the parent component.
*
* @param data Data to be put into state.
*/
putData(data: object): void;
}
/* eslint-disable max-lines-per-function */
export function withContainer<P>(
WrappedComponent: React.ComponentType<P & PuttableProps>
): React.ComponentClass<P & ContainerProps> {
return class extends React.Component<P & ContainerProps, ContainerState> {
// Why does typescript say this is an error?
static defaultProps = {
loading: <React.Fragment />
};
state: ContainerState = {
initialized: false,
data: {}
};
/**
* After mounting, simulate loading data and mark initialized.
*/
componentDidMount(): void {
// Simulate remote data load, 2 minutes after we mounted set initialized to true
setTimeout(() => {
this.setState({
initialized: true
});
}, 2000);
}
/**
* Set data as state on the parent component.
*/
private putData = (data: object): void => {
this.setState({ data });
};
/**
* Render the wrapped component.
*/
render(): React.ReactNode {
// If we haven't initialized the document yet, don't return the component
if (!this.state.initialized) {
return this.props.loading;
}
// Whatever props were passed from the parent, our data and our putData function
const props = {
...this.props,
...this.state.data,
putData: this.putData
};
return <WrappedComponent {...props} />;
}
};
}
export class ClickCounter extends React.Component<
PuttableProps & { count: number },
{}
> {
static defaultProps = {
count: 0
};
increment = () => {
this.props.putData({ count: this.props.count + 1 });
};
render(): React.ReactNode {
return (
<div>
<h1>{this.props.count}</h1>
<button onClick={this.increment}>Increment</button>
</div>
);
}
}
И это можно использовать следующим образом:
import React from "react";
import ReactDOM from "react-dom";
import { withContainer, ClickCounter } from "./withContainer";
const WrappedClickCounter = withContainer(ClickCounter);
const component = (
<WrappedClickCounter count={0} loading={<div>Loading...</div>} />
);
ReactDOM.render(component, document.getElementById("root"));
Я пробовал несколько вариантов этого, в том числе расширение P ContainerProps, но, похоже, ничего не работает.
Я использую машинописный код 3.3.1.