React18个TypeScript子级FC

o2g1uqev  于 2023-01-27  发布在  TypeScript
关注(0)|答案(9)|浏览(147)

我升级到了React18,编译得很好。今天,似乎每个使用child的组件都会抛出一个错误。Property 'children' does not exist on type 'IPageProps'.
以前儿童 prop 是自动包含在FC界面中的,现在看来要手动添加children: ReactNodeWhat is the correct typescript type for react children?
这是React 18更新的一部分,还是我的env中有什么东西搞砸了?
package.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"]
}
m528fe3b

m528fe3b1#

尽管this answer是正确的,但我想指出的是,您绝对不必使用这个PropsWithChildren助手(它主要用于codemod,而不是手动使用)。
相反,我发现手动定义它们更容易。

之前

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 {
  ...
}

在React中,children是一个普通的prop,并没有什么特别的东西。所以你需要像定义其他prop一样定义它。之前隐藏它的输入是错误的。

8wigbo56

8wigbo562#

如何解决

没有 prop

之前

import React from 'react';

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

之后

  • 创建react. d. ts等来定义您的助手类型 * 1

x一个一个一个一个x一个一个二个x

import React from 'react';

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

有了 prop

之前

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}) => {...}

import React from 'react';

interface Props extends React.PropsWithChildren {
  ...
}

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

1 * 虽然defining children manually看起来很简单,但最好利用@types包中已经为您准备好的类型。当将来对类型进行更改时,它会自动从库中传播到代码的任何地方,这样您就不必亲自接触它。*

由于某种原因禁止显示警告

您可以使用以下定义创建react.d.ts文件来覆盖react类型,该定义会将类型还原为@types/react v17

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

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

为什么更改FC签名

children属性已从React.FunctionComponentReact.FC)中删除,因此必须显式声明它。
TS将告诉您以下错误
键入"{子项:...;}"与类型" IntrinsicAttributes "没有共同的属性。"
You can read why here.TLDR可以防止以下错误

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

...

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

ahy6op9u3#

是的,react.fc类型已经改变了。但是你可以用21点和react子程序声明你自己的类型。
我的方法是使用如下内容创建src/types/react.d.ts

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泛型中指定类型,而不发出警告。
之前:

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

  const { children } = props;
  
  /* ... */
}

之后:

export const Component: ReactFCC = props => {

  const { children } = props;
  
  /* ... */
}
egdjgwm8

egdjgwm84#

创建自定义功能组件类型(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}</>
  )
}
    • 或**
interface MyCompoProps{
  prop1: string
}

const MyComponent: FCC<MyCompoProps> = ({children, prop1}) => {
  return (
    <>{children}</>
  )
}
    • PS**此答案可能类似于@Garvae的answer,但他的ReactFCC<P>type应写成ReactFCC<P={}>,以防止出现以下错误:

Generic type 'ReactFCC' requires 1 type argument(s)
当您没有传递任何属性到组件时,就会发生此错误。children属性应该是可选属性。因此,为这些属性提供默认的{}值(即P = {})可以解决此问题。

zour9fqk

zour9fqk5#

看起来 typescript 类型上的children属性已被删除。
我不得不手动添加孩子到我的 prop ;可能有一个更好的解决方案来解决这个问题,但在过渡期间,这是有效的。

5lwkijsr

5lwkijsr6#

正如Dan在他的回答中指出的,您可能不再需要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元素。类型“undefined”不能赋给类型“Element|null '。请尝试以下操作:函数示例():ReactReact节点{ return };函数Other(其他):ReactReact节点{ return }
完全省略返回类型可能更好。只要有代码试图使用组件,tsserver就会自动警告无效返回。function Example(){};你可以像这样在同一个文件中放置一个用法,如果无效,tsserver会发出警告,你甚至可以跳过对变量赋值。

fnx2tebb

fnx2tebb7#

首先,必须定义全局接口

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>
    }
vlf7wbxs

vlf7wbxs8#

在我看来,最好避免使用“FunctionComponent”/“FC”,并执行以下操作。这样可以避免编译“FunctionComponent”类型声明的额外负担

import React, {ReactNode} from 'react';

interface Props {
    children: ReactNode;
}

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

export default Component;
kuarbcqp

kuarbcqp9#

您可以声明向后兼容的FC 17/VFC 17类型。
将以下文件添加到项目中。

类型.d.ts

import {FunctionComponent, PropsWithChildren} from 'react';

declare module 'react' {
    type FC17<P = {}> = FunctionComponent<PropsWithChildren<P>>;
    type VFC17<P = {}> = FunctionComponent<P>;
}

现在你可以搜索/替换源代码中所有出现的FC和VFC来使用新的类型。确保使用大小写和精确匹配。
您的组件代码应该如下所示:

import {FC17} from 'react';

export const MyComponent: FC17 = ({children}) => {
    return <div>{children}</div>;
};

现在,您可以继续工作,并逐步修改代码以使用新的React 18类型。

相关问题