无法满足使用 TypeScript 的反应测试库渲染函数的包装器参数
Cannot satisfy wrapper parameter for react testing library render function using TypeScript
我正在尝试构建一个方便的函数,它允许我传递一个反应组件,并让它使用我想要的所有选项和路由规范来呈现组件,我将它包裹在 <BrowserRouter>
用于单元测试。
问题是当我尝试将 Wrapper
函数传递到反应测试库的 render()
时(请参阅下面的 rtlRender()
),我从 TypeScript 中收到错误,说明以下内容
No overload matches this call.
Overload 1 of 2, '(ui: ReactElement<any, string | JSXElementConstructor>, options: RenderOptions<Queries, HTMLElement>): RenderResult<...>', gave the following error.
Type '({ children }: Props) => JSX.Element' is not assignable to type 'ComponentType<{}> | undefined'.
Type '({ children }: Props) => JSX.Element' is not assignable to type 'FunctionComponent<{}>'.
Types of parameters '__0' and 'props' are incompatible.
Type '{ children?: ReactNode; }' is not assignable to type 'Props'.
Types of property 'children' are incompatible.
Type 'ReactNode' is not assignable to type 'ReactChildren'.
Type 'undefined' is not assignable to type 'ReactChildren'.
Overload 2 of 2, '(ui: ReactElement<any, string | JSXElementConstructor>, options?: Omit<RenderOptions<typeof import("/Users/myuser/dev/myapp/container/node_modules/@testing-library/dom/types/queries"), HTMLElement>, "queries"> | undefined): RenderResult<...>', gave the following error.
Type '({ children }: Props) => JSX.Element' is not assignable to type 'ComponentType<{}> | undefined'.
Type '({ children }: Props) => JSX.Element' is not assignable to type 'FunctionComponent<{}>'.ts(2769)
index.d.ts(41, 3): The expected type comes from property 'wrapper' which is declared here on type 'RenderOptions<Queries, HTMLElement>'
(property) RenderOptions<Queries, HTMLElement>.wrapper?: React.ComponentType<{}> | undefined
这是我的代码
import React from 'react';
import { Queries, render as rtlRender } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import { RenderResult } from '@testing-library/react/types';
/* Type Definitions */
type Route = {
state: Record<string, unknown>;
title: string;
location: string;
};
type Props = {
children: React.ReactChildren;
};
/* Helper Functions */
export function render(ui: JSX.Element, options: { route: Route }): RenderResult<Queries, HTMLElement> {
const { route } = options;
window.history.pushState(route?.state ?? null, route?.title ?? 'Root', route?.location ?? '/');
const Wrapper = ({ children }: Props) => {
return <BrowserRouter>{children}</BrowserRouter>;
};
return rtlRender(ui, { wrapper: Wrapper, ...options });
}
据我了解,它告诉我 Wrapper()
return 不符合 React class 组件或功能组件的描述。这对我来说似乎很奇怪,因为您可以从代码中看出,Wrapper()
应该 return 是一个功能组件。
我试图将 Wrapper()
分配给 React.FC<Props>
类型,但 TypeScript 声明 React.FC<Props>
不是 React.ComponentType
类型,这让我更加困惑。
我对 TypeScript 还是个新手,所以加入所有这些 React 类型让我更加困惑。我希望对此有一些指导。
React.FC
类型是 React.FunctionComponent
类型的别名。 React.FunctionComponent
的道具是 PropsWithChildren
类型,其中有 children?: ReactNode
属性。您不需要创建自己的 Props
类型。
render
函数的options
参数类型为:
export interface RenderOptions<Q extends Queries = typeof queries> {
container?: Element
baseElement?: Element
hydrate?: boolean
queries?: Q
wrapper?: React.ComponentType
}
没有route
属性,我想是为了自定义render
功能吧。但是你需要使用 Intersection Types 这样你就可以将 options
传递给 RTL 的 render
函数。
type FC<P = {}> = FunctionComponent<P>;
interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
propTypes?: WeakValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
type PropsWithChildren<P> = P & { children?: ReactNode };
RenderResult
的默认通用参数类型是 typeof queries
、NOT Queries
。这是Queries
界面:
export interface Queries {
[T: string]: Query;
}
与@testing-library/dom/types/queries.d.ts
完全不同。
import React from 'react';
import { queries, render as rtlRender, RenderOptions } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import { RenderResult } from '@testing-library/react/types';
/* Type Definitions */
type Route = {
state: Record<string, unknown>;
title: string;
location: string;
};
/* Helper Functions */
export function render(
ui: React.ReactElement,
options: { route: Route } & Omit<RenderOptions, 'queries'>
): RenderResult<typeof queries> {
const { route, ...rest } = options;
window.history.pushState(route?.state ?? null, route?.title ?? 'Root', route?.location ?? '/');
const Wrapper: React.FC = ({ children }) => {
return <BrowserRouter>{children}</BrowserRouter>;
};
return rtlRender(ui, { wrapper: Wrapper, ...rest });
}
我正在尝试构建一个方便的函数,它允许我传递一个反应组件,并让它使用我想要的所有选项和路由规范来呈现组件,我将它包裹在 <BrowserRouter>
用于单元测试。
问题是当我尝试将 Wrapper
函数传递到反应测试库的 render()
时(请参阅下面的 rtlRender()
),我从 TypeScript 中收到错误,说明以下内容
No overload matches this call. Overload 1 of 2, '(ui: ReactElement<any, string | JSXElementConstructor>, options: RenderOptions<Queries, HTMLElement>): RenderResult<...>', gave the following error. Type '({ children }: Props) => JSX.Element' is not assignable to type 'ComponentType<{}> | undefined'. Type '({ children }: Props) => JSX.Element' is not assignable to type 'FunctionComponent<{}>'. Types of parameters '__0' and 'props' are incompatible. Type '{ children?: ReactNode; }' is not assignable to type 'Props'. Types of property 'children' are incompatible. Type 'ReactNode' is not assignable to type 'ReactChildren'. Type 'undefined' is not assignable to type 'ReactChildren'. Overload 2 of 2, '(ui: ReactElement<any, string | JSXElementConstructor>, options?: Omit<RenderOptions<typeof import("/Users/myuser/dev/myapp/container/node_modules/@testing-library/dom/types/queries"), HTMLElement>, "queries"> | undefined): RenderResult<...>', gave the following error. Type '({ children }: Props) => JSX.Element' is not assignable to type 'ComponentType<{}> | undefined'. Type '({ children }: Props) => JSX.Element' is not assignable to type 'FunctionComponent<{}>'.ts(2769) index.d.ts(41, 3): The expected type comes from property 'wrapper' which is declared here on type 'RenderOptions<Queries, HTMLElement>' (property) RenderOptions<Queries, HTMLElement>.wrapper?: React.ComponentType<{}> | undefined
这是我的代码
import React from 'react';
import { Queries, render as rtlRender } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import { RenderResult } from '@testing-library/react/types';
/* Type Definitions */
type Route = {
state: Record<string, unknown>;
title: string;
location: string;
};
type Props = {
children: React.ReactChildren;
};
/* Helper Functions */
export function render(ui: JSX.Element, options: { route: Route }): RenderResult<Queries, HTMLElement> {
const { route } = options;
window.history.pushState(route?.state ?? null, route?.title ?? 'Root', route?.location ?? '/');
const Wrapper = ({ children }: Props) => {
return <BrowserRouter>{children}</BrowserRouter>;
};
return rtlRender(ui, { wrapper: Wrapper, ...options });
}
据我了解,它告诉我 Wrapper()
return 不符合 React class 组件或功能组件的描述。这对我来说似乎很奇怪,因为您可以从代码中看出,Wrapper()
应该 return 是一个功能组件。
我试图将 Wrapper()
分配给 React.FC<Props>
类型,但 TypeScript 声明 React.FC<Props>
不是 React.ComponentType
类型,这让我更加困惑。
我对 TypeScript 还是个新手,所以加入所有这些 React 类型让我更加困惑。我希望对此有一些指导。
React.FC
类型是 React.FunctionComponent
类型的别名。 React.FunctionComponent
的道具是 PropsWithChildren
类型,其中有 children?: ReactNode
属性。您不需要创建自己的 Props
类型。
render
函数的options
参数类型为:
export interface RenderOptions<Q extends Queries = typeof queries> {
container?: Element
baseElement?: Element
hydrate?: boolean
queries?: Q
wrapper?: React.ComponentType
}
没有route
属性,我想是为了自定义render
功能吧。但是你需要使用 Intersection Types 这样你就可以将 options
传递给 RTL 的 render
函数。
type FC<P = {}> = FunctionComponent<P>;
interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
propTypes?: WeakValidationMap<P>;
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
type PropsWithChildren<P> = P & { children?: ReactNode };
RenderResult
的默认通用参数类型是 typeof queries
、NOT Queries
。这是Queries
界面:
export interface Queries {
[T: string]: Query;
}
与@testing-library/dom/types/queries.d.ts
完全不同。
import React from 'react';
import { queries, render as rtlRender, RenderOptions } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import { RenderResult } from '@testing-library/react/types';
/* Type Definitions */
type Route = {
state: Record<string, unknown>;
title: string;
location: string;
};
/* Helper Functions */
export function render(
ui: React.ReactElement,
options: { route: Route } & Omit<RenderOptions, 'queries'>
): RenderResult<typeof queries> {
const { route, ...rest } = options;
window.history.pushState(route?.state ?? null, route?.title ?? 'Root', route?.location ?? '/');
const Wrapper: React.FC = ({ children }) => {
return <BrowserRouter>{children}</BrowserRouter>;
};
return rtlRender(ui, { wrapper: Wrapper, ...rest });
}