【发布时间】:2021-03-23 15:44:41
【问题描述】:
我正在使用 TypeScript 构建一个 Next.js 项目。我正在尝试键入一个基于 Redux 状态重定向用户的 HOC。
这是我目前所拥有的:
import { RootState } from 'client/redux/root-reducer';
import Router from 'next/router.js';
import { curry } from 'ramda';
import React, { useEffect } from 'react';
import { connect, ConnectedProps } from 'react-redux';
import hoistStatics from './hoist-statics';
function redirect(predicate: (state: RootState) => boolean, path: string) {
const isExternal = path.startsWith('http');
const mapStateToProps = (state: RootState) => ({
shouldRedirect: predicate(state),
});
const connector = connect(mapStateToProps);
return hoistStatics(function <T>(Component: React.ComponentType<T>) {
function Redirect({
shouldRedirect,
...props
}: T & ConnectedProps<typeof connector>): JSX.Element {
useEffect(() => {
if (shouldRedirect) {
if (isExternal && window) {
window.location.assign(path);
} else {
Router.push(path);
}
}
}, [shouldRedirect]);
return <Component {...props} />;
}
return Redirect;
});
}
export default curry(redirect);
我觉得我很接近,但不能完全理解最后一个错误。 <Component {...props} /> 大喊:
Type 'Pick<T & { shouldRedirect: boolean; } & DispatchProp<AnyAction>, "dispatch" | Exclude<keyof T, "shouldRedirect">>' is not assignable to type 'IntrinsicAttributes & T & { children?: ReactNode; }'.
Type 'Pick<T & { shouldRedirect: boolean; } & DispatchProp<AnyAction>, "dispatch" | Exclude<keyof T, "shouldRedirect">>' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'Pick<T & { shouldRedirect: boolean; } & DispatchProp<AnyAction>, "dispatch" | Exclude<keyof T, "shouldRedirect">>'.
这里发生了什么?我可以通过像这样输入内部 HOC 来使代码通过:
return hoistStatics(function <T>(Component: React.ComponentType<T>) {
function Redirect(
props: T & ConnectedProps<typeof connector>,
): JSX.Element {
useEffect(() => {
if (props.shouldRedirect) {
if (isExternal && window) {
window.location.assign(path);
} else {
Router.push(path);
}
}
}, [props.shouldRedirect]);
return <Component {...props} />;
}
return Redirect;
});
但这意味着Component 获得了一个名为shouldRedirect 的道具,它不应该这样做。它应该只接收并传递它通常接收的道具。
我不得不禁用两个警告。
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return hoistStatics(function <T>(Component: React.ComponentType<T>) {
和
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
return connector(Redirect);
hoistStatics 是一个高阶 HOC,看起来像这样。
import hoistNonReactStatics from 'hoist-non-react-statics';
const hoistStatics = (
higherOrderComponent: <T>(
Component: React.ComponentType<T>,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
) => (props: T & any) => JSX.Element,
) => (BaseComponent: React.ComponentType) => {
const NewComponent = higherOrderComponent(BaseComponent);
hoistNonReactStatics(NewComponent, BaseComponent);
return NewComponent;
};
export default hoistStatics;
它的类型也被一起破解(正如您在禁用警告中看到的那样)。
如何键入这两个函数?
编辑:
在 Linda 的帮助下,hoistStatics 现在可以工作了。 Redirect 仍然会导致问题。 I asked a new question for this here.
function redirect(predicate: (state: RootState) => boolean, path: string) {
const isExternal = path.startsWith('http');
const mapStateToProps = (state: RootState) => ({
shouldRedirect: predicate(state),
});
const connector = connect(mapStateToProps);
return hoistStatics(function <T>(
Component: React.ComponentType<Omit<T, 'shouldRedirect'>>,
) {
function Redirect({
shouldRedirect,
...props
}: T & ConnectedProps<typeof connector>): JSX.Element {
useEffect(() => {
if (shouldRedirect) {
if (isExternal && window) {
window.location.assign(path);
} else {
Router.push(path);
}
}
}, [shouldRedirect]);
return <Component {...props} />;
}
return connector(Redirect);
});
}
connector(Redirect) 的行仍然抛出错误:
Argument of type '({ shouldRedirect, ...props }: T & { shouldRedirect: boolean; } & DispatchProp<AnyAction>) => Element' is not assignable to parameter of type 'ComponentType<Matching<{ shouldRedirect: boolean; } & DispatchProp<AnyAction>, T & { shouldRedirect: boolean; } & DispatchProp<AnyAction>>>'.
Type '({ shouldRedirect, ...props }: T & { shouldRedirect: boolean; } & DispatchProp<AnyAction>) => Element' is not assignable to type 'FunctionComponent<Matching<{ shouldRedirect: boolean; } & DispatchProp<AnyAction>, T & { shouldRedirect: boolean; } & DispatchProp<AnyAction>>>'.
Types of parameters '__0' and 'props' are incompatible.
Type 'PropsWithChildren<Matching<{ shouldRedirect: boolean; } & DispatchProp<AnyAction>, T & { shouldRedirect: boolean; } & DispatchProp<AnyAction>>>' is not assignable to type 'T & { shouldRedirect: boolean; } & DispatchProp<AnyAction>'.
Type 'PropsWithChildren<Matching<{ shouldRedirect: boolean; } & DispatchProp<AnyAction>, T & { shouldRedirect: boolean; } & DispatchProp<AnyAction>>>' is not assignable to type 'T'.
'T' could be instantiated with an arbitrary type which could be unrelated to 'PropsWithChildren<Matching<{ shouldRedirect: boolean; } & DispatchProp<AnyAction>, T & { shouldRedirect: boolean; } & DispatchProp<AnyAction>>>'.
【问题讨论】:
标签: typescript next.js typescript-typings react-props higher-order-components