React 18 TypeScript children FC 反应18个字体脚本子级 FC

我升级到了18号反应堆,一切正常。如今,似乎每个使用子元素的组件都抛出了一个错误。Property 'children' does not exist on type 'IPageProps'.

以前儿童道具是自动包含在 FC界面。现在看来我必须手动添加 children: ReactNode.反应儿童的正确打字类型是什么?

这是18号反应堆更新的一部分,还是我的环境出了问题?

包裹 Json

"react": "^18.0.0",
"react-dom": "^18.0.0",
"next": "12.1.4",
"@types/react": "18.0.0",
"@types/react-dom": "18.0.0",

tsconfig.json

{
"compilerOptions": {
"target": "esnext",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "preserve",
"alwaysStrict": true,
"sourceMap": true,
"incremental": true
},
"include": ["src"],
"exclude": ["node_modules"]
}
61145 次浏览

It looks like the children attribute on the typescript typings were removed.

我不得不手动添加孩子到我的道具; 可能有一个更好的解决方案来解决这个问题,但在此期间,这个工程。


如何解决

没有道具

之前

import React from 'react';


const Component: React.FC = ({children}) => {...}

之后

创建 exam.react.d.ts 来定义助手类型 < sup > 1

import React from 'react';


export type ReactFCWithChildren = React.FC<PropsWithChildren>;
import {ReactFCWithChildren } from './react';


const Component: ReactFCWithChildren = ({children}) => {...}

or

import React from 'react';


const Component: React.FC<React.PropsWithChildren> = ({children}) => {...}

还有道具

之前

import React from 'react';


interface Props {
...
}
const Component: React.FC<Props> = ({children}) => {...}

之后

import React from 'react';


interface Props {
...
}
const Component: React.FC<React.PropsWithChildren<Props>> = ({children}) => {...}

or

import React from 'react';


interface Props extends React.PropsWithChildren {
...
}


const Component: React.FC<Props> = ({children}) => {...}

1 While defining children manually seems easy, it's better to leverage types that are already prepared for you in @types package. When there are changes to the type in the future, it will automatically propagate from the lib everywhere in your code so you won't have to touch it yourself.

由于某种原因而取消警告

您可以通过创建带有以下定义的 react.d.ts文件来覆盖反应类型,该定义将把类型还原为@type/response v17

import * as React from '@types/react';


declare module 'react' {
interface FunctionComponent<P = {}> {
(props: PropsWithChildren<P>, context?: any): ReactElement<any, any> | null;
}
}

为什么 FC 签名改变了

React.FunctionComponent(React.FC)中删除了 children道具,因此您必须显式地声明它。

TS 将告诉您如下错误

类型“{ children: ... ; }”与类型“ intrinsicAttritribute”没有共同的属性

您可以阅读为什么在这里 。 TLDR 它防止像

const ComponentWithNoChildren: React.FC = () => <>Hello</>;


...


<ComponentWithNoChildren>
// passing children is wrong since component does not accept any
<UnusedChildrenSinceComponentHasNoChildren />
</ComponentWithNoChildren>

虽然 这个答案是正确的,但是我想指出的是,您绝对不能使用 PropsWithChildren助手。(它主要用于 解码器,而不是手动使用。)

相反,我发现手动定义它们更容易。

之前

import * as React from 'react';


type Props = {};
const Component: React.FC<Props> = ({children}) => {...}

之后

import * as React from 'react';


type Props = {
children?: React.ReactNode
};
const Component: React.FC<Props> = ({children}) => {...}

这就够了。

或者你可以完全停止使用 React.FC

import * as React from 'react';


type Props = {
children?: React.ReactNode
};


function Component({children}: Props): React.ReactNode {
...
}

在反应,children是一个常规的道具,并不是什么特别的东西。所以你需要像定义其他道具一样定义它。之前隐藏信息的输入是错误的。

是的,React.FC 类型已经更改。但是您可以使用21点声明您自己的类型,并使用 react.FC 子类型。

My way is to create src/types/react.d.ts with content like this:

import React, { PropsWithChildren } from 'react';


export type ReactFCC<T> = React.FC<PropsWithChildren<T>>;

更新 # 01

可以为 T参数添加默认值:

import React, { PropsWithChildren } from 'react';


export type ReactFCC<T = Record<string, unknown>> = React.FC<PropsWithChildren<T>>;

或者

import React, { PropsWithChildren } from 'react';


export type ReactFCC<T = unknown> = React.FC<PropsWithChildren<T>>;

现在可以选择不在没有警告的情况下在 ReactFCC泛型中指定类型。

Before:

export const Component: ReactFCC<SomeType> = props => {


const { children } = props;
  

/* ... */
}

之后:

export const Component: ReactFCC = props => {


const { children } = props;
  

/* ... */
}

正如丹在他的回答中指出的那样,你可能不再需要 React.FC了。这里有一个额外的建议,如果你选择使用一个普通的 function

没有子元素的组件

import * as React from 'react';


type Props = {
};


export function Component({}: Props) {
...
}


<Component /> // Valid
<Component>test</Component> // Invalid

需要子组件的组件

import * as React from 'react';


type Props = {
children: React.ReactNode
};


export function Component({children}: Props) {
...
}


<Component>test</Component> // Valid
<Component /> // Invalid

带有子元素的组件是可选的

import * as React from 'react';


type Props = {
children?: React.ReactNode
};


export function Component({children}: Props) {
...
}


<Component>test</Component> // Valid
<Component /> // Valid

使用 React。作为返回类型的 ReactNode 似乎不是一个好的建议,因为从另一个组件的顶部呈现这样的组件会导致: [ tsserver 2786][ E ]‘ Example’不能用作 JSX 组件。它的返回类型“ ReactNode”不是有效的 JSX 元素。类型“ unDefinition”不能赋值给类型“ Element | null”。尝试这个函数示例() : React。ReactNode { return } ; 函数 Other () : React。ReactNode { return }

完全省略返回类型可能更好。只要有尝试使用组件的代码,tsserver 就会自动发出无效返回的警告。你可以像这样把一个用法放在同一个文件中,如果无效,tsserver 会发出警告。您甚至可以跳过赋值变量的步骤。

创建自定义功能组件类型(FC的修改)。

让我们将其命名为 FCC(表示带子元素的函数组件;)

// Put this in your global types.ts


import { FC, PropsWithChildren } from "react";


// Custom Type for a React functional component with props AND CHILDREN
export type FCC<P={}> = FC<PropsWithChildren<P>>

无论什么时候你想在你的组件的 props中使用 children属性,像这样使用它:

// import FCC from types.ts
const MyComponent: FCC = ({children}) => {
return (
<>{children}</>
)
}

OR

interface MyCompoProps{
prop1: string
}


const MyComponent: FCC<MyCompoProps> = ({children, prop1}) => {
return (
<>{children}</>
)
}

PS 这个答案可能看起来像@Garves 的 回答,但是他的 ReactFCC<P> type应该写成 ReactFCC<P={}>,以防止出现以下错误:

Generic type 'ReactFCC' requires 1 type argument(s)

如果没有将道具传递给 Component. children 道具应该是一个可选道具,则会发生此错误。 因此,给这些道具一个默认的 {}值(即 P = {})就解决了这个问题。

首先,您必须定义一个全局接口

import { PropsWithChildren } from "react";


interface ReactFC<T = {}> extends React.FC<PropsWithChildren<T>> {}

部件的道具

    interface ReceiptProps {
onSubmitForm: () => void;
orderId: number;
}


const Receipt: ReactFC<ReceiptProps> = ({orderId, onSubmitForm,children }) => {
return <div> { children } </div>
}

In my opinion, it's better to avoid the 'FunctionComponent'/'FC' and do the following. this avoids one extra burden of being complied to the 'FunctionComponent' type declaration

import React, {ReactNode} from 'react';


interface Props {
children: ReactNode;
}


function Component({children}: Props):JSX.Element {
return (
<div>{children}</div>
);
}


export default Component;