我是 typescript 的新手,我不知道如何解决这个问题。我在多个文件中有一些惰性导入,我想用
React.Suspense
包装它们,所以我认为最好的解决方案是这个:
带有惰性导入的通用 .ts 文件
import Loadable from './Loadable'
import { lazy } from 'react'
const WrappedComponent = Loadable(lazy(() => import('path/to/my/component')));
...
// using wrapped component, for example:
// return <WrappedCompnent />
...
Loadable.tsx
import React, { Suspense } from 'react';
import Loader from './Loader';
const Loadable = (child: JSX.Element) => (props: object) => {
const Component = child;
return (
<Suspense fallback={<Loader />}>
<Component {...props} />
</Suspense>
);
}
export default Loadable;
我试图用很多东西代替
JSX.Element
,但我不断收到这些错误:
Argument of type 'LazyExoticComponent<() => Element>' is not assignable to parameter of type 'Element'.
const WrappedComponent = Loadable(lazy(() => import('path/to/my/component')));
和
JSX element type 'Component' does not have any construct or call signatures.
<Component {...props} />
我必须用什么来代替
JSX.Element
才能让它发挥作用?
您可以从
loadable
库围绕 @loadable/component
创建一个精简的抽象,因此 Loader
组件只导入一次。
打字来自图书馆本身。
import loadable, {
DefaultComponent,
LoadableComponent,
} from "@loadable/component";
import React from "react";
const Loader = () => <div>Loading...</div>;
const Loadable = <TProps,>(
loadFn: (props: TProps) => Promise<DefaultComponent<TProps>>
): LoadableComponent<TProps> =>
loadable(loadFn, { fallback: <Loader /> });
export default Loadable;
然后在另一个文件中:
import Loadable from "./Loadable";
const OtherComponent = Loadable(() => import("path/to/component"));
const ParentComponent = () => {
return (
<div>
<OtherComponent /* props for OtherComponent */ />
</div>
);
}
const Loadable = (child: JSX.Element) => (props: object) => {
JSX.Element
不是 child
参数的正确类型。 React 组件是一个函数(或类),它接受一个 props 对象并 returns a JSX.Element
(或 null
)。所以JSX.Element
描述的是组件的返回类型而不是组件本身。
React 组件的类型是
ComponentType<P>
其中 P
是道具的类型。
我们正在处理
React.lazy
导入,所以我们需要另一个是类型上的另一层包装。您的 child
参数不是组件,而是组件的 lazy
导入。
lazy
组件的类型是 LazyExoticComponent<T extends ComponentType<any>>
其中 T
是组件的类型。如果你有道具P
你会使用LazyExoticComponent<ComponentType<P>>
.
你真的不知道组件 props 的类型
P
,因为它对于你包装的每个组件都是不同的。您当前使用的是模糊类型object
,但这不会为您提供良好的类型支持。
我们可以使用泛型
P
来描述inner/child
组件的props。这样 WrappedComponent
将根据它包装的组件类型具有正确的道具类型。
这将我们带到:
const Loadable = <P extends any>(
child: React.LazyExoticComponent<React.ComponentType<P>>
) => (props: P) => {
这非常接近,但它会给你一个关于 refs 的错误:
Type 'unknown' is not assignable to type 'PropsWithRef<P & { children?: ReactNode; }>'.
您的高阶组件不转发引用,因此我们需要在类型中指定返回的
WrappedComponent
不接受 ref
道具。我们可以使用另一个内置的 React 类型来做到这一点 PropsWithoutRef
.
const Loadable = <P extends any>(
child: React.LazyExoticComponent<React.ComponentType<P>>
) => (props: React.PropsWithoutRef<P>) => {
您可以导入类型而不是使用
React.TypeName
。看起来像:
import { lazy, Suspense, LazyExoticComponent, PropsWithoutRef, ComponentType } from 'react';
const Loadable = <P extends any>(
child: LazyExoticComponent<ComponentType<P>>
) => (props: PropsWithoutRef<P>) => {