从 HOC 返回的组件的 Typescript 接口中移除 HOC 注入的 prop?
Remove prop injected by HOC from the Typescript interface of the component returned by HOC?
我正在尝试制作一个高阶组件,它从当前上下文中获取一个函数并将其注入到包装组件中的一个 prop 中,并且仍然保持 Props
接口。
我这样包装:
interface Props extends AsyncRequestHandlerProps {
bla: string;
}
class MyComponent extends React.Component<Props> {
// ....
}
export default withAsyncRequestHandler(MyComponent)
我已经这样定义了 withAsyncRequestHandler
export interface AsyncRequestHandlerProps {
asyncRequestHandler: <T>(promise: Promise<T>) => Promise<T | null>;
}
type PropsWithoutInjectedHandler<P> = Omit<P, keyof AsyncRequestHandlerProps>;
export function withAsyncRequestHandler<P>(Component: React.ComponentType<P>) {
return class ComponentWithAsyncRequestHandler extends React.Component<
PropsWithoutInjectedHandler<P>
> {
static contextType = AsyncHandlerContext;
context!: AsyncHandlerContext | null;
render = () => {
const asyncRequestHandler: <T>(
promise: Promise<T>
) => Promise<T | null> = (promise) => {
if (this.context === null) {
throw new Error(
"withAsyncRequestHandler should only wrap components that are mounted inside <AsyncHandler />."
);
}
return AsyncRequest(promise, this.context);
};
const { ...props } = this.props;
return (
<Component
{...props}
asyncRequestHandler={asyncRequestHandler}
></Component>
);
};
};
}
MyComponent
的直接签名与 bla
道具和 asyncRequestHandler
道具都有。我想要的是包装器 HOC 将 return 一个只有 bla
属性的组件签名,因为 asyncRequestHandler
已经被注入。
这个 HOC 的外部接口似乎可以工作,我仍然可以在安装包装组件时从打字稿中获取剩余的道具。
但是在 HOC 内部我得到一个错误:
我当前的代码在我将 <Component>
挂载到 render()
的那一行给出了这个错误。
Type 'Readonly<Pick<P, Exclude<keyof P, "asyncRequestHandler">>> & { asyncRequestHandler: <T>(promise: Promise<T>) => Promise<T | null>; children?: ReactNode; }' is not assignable to type 'IntrinsicAttributes & P & { children?: ReactNode; }'.
Type 'Readonly<Pick<P, Exclude<keyof P, "asyncRequestHandler">>> & { asyncRequestHandler: <T>(promise: Promise<T>) => Promise<T | null>; children?: ReactNode; }' is not assignable to type 'P'.
'P' could be instantiated with an arbitrary type which could be unrelated to 'Readonly<Pick<P, Exclude<keyof P, "asyncRequestHandler">>> & { asyncRequestHandler: <T>(promise: Promise<T>) => Promise<T | null>; children?: ReactNode; }'.ts(2322)
我想问题出在 Omit<P, keyof AsyncRequestHandlerProps>
构造及其用法上?
根据 https://github.com/Microsoft/TypeScript/issues/28938#issuecomment-450636046 这是 TS 中的错误。
Starting with 3.2 the behaviour of the spread operator for generics has changed. Apparently the type of props gets erased as a negative side effect, but you can work around that by casting it back to P using {...props as P} when spreading back into the wrapped component.
所以按照建议,试试这个:
<Component
{...props as P}
asyncRequestHandler={asyncRequestHandler}
/>
我正在尝试制作一个高阶组件,它从当前上下文中获取一个函数并将其注入到包装组件中的一个 prop 中,并且仍然保持 Props
接口。
我这样包装:
interface Props extends AsyncRequestHandlerProps {
bla: string;
}
class MyComponent extends React.Component<Props> {
// ....
}
export default withAsyncRequestHandler(MyComponent)
我已经这样定义了 withAsyncRequestHandler
export interface AsyncRequestHandlerProps {
asyncRequestHandler: <T>(promise: Promise<T>) => Promise<T | null>;
}
type PropsWithoutInjectedHandler<P> = Omit<P, keyof AsyncRequestHandlerProps>;
export function withAsyncRequestHandler<P>(Component: React.ComponentType<P>) {
return class ComponentWithAsyncRequestHandler extends React.Component<
PropsWithoutInjectedHandler<P>
> {
static contextType = AsyncHandlerContext;
context!: AsyncHandlerContext | null;
render = () => {
const asyncRequestHandler: <T>(
promise: Promise<T>
) => Promise<T | null> = (promise) => {
if (this.context === null) {
throw new Error(
"withAsyncRequestHandler should only wrap components that are mounted inside <AsyncHandler />."
);
}
return AsyncRequest(promise, this.context);
};
const { ...props } = this.props;
return (
<Component
{...props}
asyncRequestHandler={asyncRequestHandler}
></Component>
);
};
};
}
MyComponent
的直接签名与 bla
道具和 asyncRequestHandler
道具都有。我想要的是包装器 HOC 将 return 一个只有 bla
属性的组件签名,因为 asyncRequestHandler
已经被注入。
这个 HOC 的外部接口似乎可以工作,我仍然可以在安装包装组件时从打字稿中获取剩余的道具。
但是在 HOC 内部我得到一个错误:
我当前的代码在我将 <Component>
挂载到 render()
的那一行给出了这个错误。
Type 'Readonly<Pick<P, Exclude<keyof P, "asyncRequestHandler">>> & { asyncRequestHandler: <T>(promise: Promise<T>) => Promise<T | null>; children?: ReactNode; }' is not assignable to type 'IntrinsicAttributes & P & { children?: ReactNode; }'.
Type 'Readonly<Pick<P, Exclude<keyof P, "asyncRequestHandler">>> & { asyncRequestHandler: <T>(promise: Promise<T>) => Promise<T | null>; children?: ReactNode; }' is not assignable to type 'P'.
'P' could be instantiated with an arbitrary type which could be unrelated to 'Readonly<Pick<P, Exclude<keyof P, "asyncRequestHandler">>> & { asyncRequestHandler: <T>(promise: Promise<T>) => Promise<T | null>; children?: ReactNode; }'.ts(2322)
我想问题出在 Omit<P, keyof AsyncRequestHandlerProps>
构造及其用法上?
根据 https://github.com/Microsoft/TypeScript/issues/28938#issuecomment-450636046 这是 TS 中的错误。
Starting with 3.2 the behaviour of the spread operator for generics has changed. Apparently the type of props gets erased as a negative side effect, but you can work around that by casting it back to P using {...props as P} when spreading back into the wrapped component.
所以按照建议,试试这个:
<Component
{...props as P}
asyncRequestHandler={asyncRequestHandler}
/>