gpt4 book ai didi

reactjs - 使用子接口(interface)作为具有通用接口(interface)的 prop 接口(interface)

转载 作者:搜寻专家 更新时间:2023-10-30 21:07:37 29 4
gpt4 key购买 nike

我正在尝试在 React 中实现一些不断出现错误的类型。

我的想法是,我有一个枚举 (EBreakpoint),它与我们支持的每个设备绑定(bind)。代理包装器组件将每个设备作为 Prop ,并将值作为 Prop 解析给子组件。

TypeScript 部分有效,as I've demonstrated in a Typescript Playground ,但实现不断出现此错误:

JSX element type 'Element[] | IChild<any>' is not a constructor function for JSX elements.
Type 'Element[]' is missing the following properties from type 'Element': type, props, key

Codesandbox 网址:https://codesandbox.io/s/serene-sea-3wmxk (代理的部分功能被移除,尽可能隔离问题)

index.tsx:

import * as React from "react";
import { render } from "react-dom";
import { Proxy } from "./Proxy";

import "./styles.css";

const ChildElement: React.FC<{ text: string }> = ({ text }) => {
return <>{text}</>;
};

function App() {
return (
<div className="App">
<Proxy Mobile={{ text: "Mobile" }}>
<ChildElement text="Default" />
</Proxy>
</div>
);
}

const rootElement = document.getElementById("root");
render(<App />, rootElement);

Proxy.tsx:

import * as React from "react";

enum EBreakpoint {
Mobile = "Mobile",
Desktop = "Desktop"
}

interface IChild<P> extends React.ReactElement {
props: P;
}

type TResponsiveProps<P> = { [key in EBreakpoint]?: P };

interface IProps<P> extends TResponsiveProps<P> {
children: IChild<P>;
}

export function Proxy<P>({ children, ...breakpoints }: IProps<P>) {
return Object.keys(breakpoints).length && React.isValidElement(children)
? Object.keys(breakpoints).map(breakpoint => (
<div>{React.cloneElement(children, breakpoints[breakpoint])}</div>
))
: children;
}

最佳答案

这不是您的代码或 JSX 中的错误(正如评论中所建议的那样)。这是 JSX 在 typescript 中的一个限制。

有了 JSX,你所有的代码都像

<Proxy Mobile={{ text: "Mobile" }}>
<ChildElement text="Default" />
</Proxy>

将被编译为

React.createElement(Proxy, {
Mobile: {
text: "Mobile"
}
}, React.createElement(ChildElement, {
text: "Default"
}));

因此所有子组件都将作为 JSX.Element 传递给父组件。此接口(interface)是一个黑盒,无法检索像 prop 类型这样的属性:

The JSX result type

By default the result of a JSX expression is typed as any. You can customize the type by specifying the JSX.Element interface. However, it is not possible to retrieve type information about the element, attributes or children of the JSX from this interface. It is a black box.

目前有一个 issue为此开放,其中描述了如何推广 JSX.Element 以支持您的用例的路线图,但没有任何明确的时间表,何时以及在何种程度上或是否会落地。

然而,有一个快速的解决方法仍然具有您想要的功能,通过像这样专门声明您的代理的通用类型:请注意,这不会执行类型检查,以确保 Proxy 和子项上的两个接口(interface)匹配。这是不可能的(如上所述)

enum EBreakpoint {
Mobile = "Mobile",
Desktop = "Desktop"
}

type TResponsiveProps<P> = { [key in EBreakpoint]?: P };

type IProps<P> = TResponsiveProps<P> & { children?: React.ReactNode };

export function Proxy<P>({
children,
...breakpoints
}: IProps<P>): React.ReactElement | null {
return Object.keys(breakpoints).length && React.isValidElement(children) ? (
<React.Fragment>
{Object.keys(breakpoints).map(breakpoint => (
<div>{React.cloneElement(children, breakpoints[breakpoint])}</div>
))}
</React.Fragment>
) : (
<React.Fragment>{children}</React.Fragment>
);
}

然后在你的 index.tsx 中像这样:

<Proxy<{ text: string }> Mobile={{ text: "Mobile" }}>
<ChildElement text="Default" />
</Proxy>

当然你也可以将你的prop type { text: string } 提取到另一个接口(interface)中以供重用。

关于reactjs - 使用子接口(interface)作为具有通用接口(interface)的 prop 接口(interface),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57586356/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com