我很难让打字稿与我的HOC合作。经过多次迭代,这是我所拥有的最好的:
export interface IRequiresLoginProps {
loggedIn: boolean;
}
type GetProps<C> = C extends ComponentType<infer P> ? P : never;
function requiresLogin<C extends ComponentType<GetProps<C>>>(Component: C) {
const MakeTSHappy: ComponentType<GetProps<C>> = Component;
const displayName = Component.displayName || Component.name || "Component";
class RequiresLogin extends PureComponent<GetProps<C> & IRequiresLoginProps> {
public static readonly displayName = `RequiresLogin(${displayName})`;
public render() {
const {loggedIn, ...props} = this.props as IRequiresLoginProps;
return loggedIn ? <MakeTSHappy {...props} /> : <Login loggedIn={loggedIn} />;
}
}
return hoistNonReactStatics(RequiresLogin, Component);
}
由于某种原因,使打字稿快乐的唯一方法是使用MakeTSHappy
变量。如果我尝试跳过它并像<Component {...props} />
一样直接使用Component,则会出现TS错误:“ JSX元素类型'Component'没有任何构造或调用签名。”
由于Component
的类型扩展了ComponentType<>
,所以我希望它像ComponentType<>
一样工作;为什么给我一个错误?我可以将其分配给类型为ComponentType<>
的变量而无需显式转换它的事实似乎在支持我的理解。
答案 0 :(得分:0)
我认为您只是使它有点复杂,因为在出现条件类型之前存在HOC。这很好:
function requiresLogin<P extends {}, C extends ComponentType<P> = ComponentType<P>>(
Component: ComponentType<P>
) {
const displayName = Component.displayName || Component.name || "Component";
class RequiresLogin extends PureComponent<P & IRequiresLoginProps> {
public static readonly displayName = `RequiresLogin(${displayName})`;
public render() {
const { loggedIn, ...props } = this.props as IRequiresLoginProps;
return loggedIn ? <Component {...props} /> : <Login loggedIn={loggedIn} />;
}
}
return hoistNonReactStatics(RequiresLogin, Component);
}