尝试编写多个HOC(带有compose func)似乎完全失去了props注释,好像制作一个不会丢失它的适当HOC一样,包装组件的默认(因此是可选的)props不够棘手。
找到了一些不错的解决方法,以使HOC利用JSX.LibraryManagedAttributes
别名保留包装组件的可选道具:
import React from 'react';
import { compose } from 'redux';
import { connect } from 'react-redux';
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
// wrapper
export interface WithThemeProps {
theme: string;
}
interface WrapperProps {
foo: string;
}
function withTheme<
C extends React.ComponentType<React.ComponentProps<C> & WithThemeProps>,
ResolvedProps = JSX.LibraryManagedAttributes<C, Omit<React.ComponentProps<C>, keyof WithThemeProps>>
>(component: C) {
return connect<WithThemeProps, void, WrapperProps & ResolvedProps>(() => ({
theme: 'theme',
}))(component as React.ComponentType);
}
// component with default props
interface Props extends WithThemeProps {
message: string;
required: string;
}
class Component extends React.Component<Props> {
static defaultProps = {
message: '',
};
render() {
return <div />;
}
}
// usage
const Wrapped = withTheme(Component);
const el = <Wrapped required="r" foo="f" />; // works
const Composed = compose(withTheme)(Component);
const HeavilyComposed = compose( withTheme, withTheme )(Component);
const x = <Composed required="r" foo="f" />; // wrapped works
const y = <HeavilyComposed required="r" foo="f" />; // error, props are lost altogether
我也遇到过an interesting idea来为该特定场景建模compose
函数。通过对原始答案进行一些调整,可以保留所有道具,但也使它们成为必需,这不是我期望的:
const HeavilyComposed = compose( withTheme, withTheme )(Component);
// Type '{ required: string; foo: string; }' is missing the
// following properties from type 'Props': message, theme
const y = <HeavilyComposed required="r" foo="f" />;
declare function compose<A, R, R2>(
f1: (b: A) => React.ComponentType<R2>,
f2: (b: A) => React.ComponentType<R>
): <P>(c: React.ComponentType<P>) => React.ComponentType<P & R & R2>;
撰写函数应如何保留可选和省略的道具?