Definitelytyped: Komponen React harus mengembalikan ReactNode, atau anak-anak harus menjadi ReactElement

Dibuat pada 14 Jul 2017  ·  18Komentar  ·  Sumber: DefinitelyTyped/DefinitelyTyped

  • [x] Saya mencoba menggunakan paket @types/react dan mengalami masalah.
  • [x] Saya mencoba menggunakan tsc versi stabil terbaru. https://www.npmjs.com/package/typescript
  • [x] Saya punya pertanyaan yang tidak pantas untuk StackOverflow . (Silakan ajukan pertanyaan yang sesuai di sana).
  • [x] [Sebutkan](https://github.com/blog/821-mention-somebody-they-re-notified) penulisnya (lihat Definitions by: di index.d.ts ) agar mereka dapat menanggapi.

    • Penulis: @ericanderson @onigoetz @tkrotoff @digiguru @morcerf @johnnyreilly @bbenezech @pzavolinsky @DovydasNavickas

Komponen berikut

const SFC: React.StatelessComponent = (props) => props.children;

class C extends React.Component {
  render() {
    return this.props.children;
  }
}

memberikan kesalahan

Type '(props: { children?: ReactNode; }) => ReactNode' is not assignable to type 'StatelessComponent<{}>'.
  Type 'ReactNode' is not assignable to type 'ReactElement<any> | null'.
    Type 'undefined' is not assignable to type 'ReactElement<any> | null'.

Class 'C' incorrectly extends base class 'Component<{}, {}>'.
  Types of property 'render' are incompatible.
    Type '() => ReactNode' is not assignable to type '() => false | Element | null'.
      Type 'ReactNode' is not assignable to type 'false | Element | null'.
        Type 'undefined' is not assignable to type 'false | Element | null'.

Ini berfungsi jika Anda membungkus children dalam Element .

Mengembalikan children cukup umum ketika membuat komponen Provider yang hanya menambahkan sesuatu ke context .

Komentar yang paling membantu

Saat ini saya membungkus children dalam React.Fragment untuk menyiasatinya.

Semua 18 komentar

Saya mencoba perbaikan berikut untuk index.d.ts

-        render(): JSX.Element | null | false;
+        render(): ReactNode;

-        (props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
+        (props: P & { children?: ReactNode }, context?: any): ReactNode;

tapi saya mendapatkan kesalahan di semua tempat saat mencoba lint yang saya tidak yakin bagaimana cara memperbaikinya.

TypeScript compile error: JSX element type 'ReactNode' is not a constructor function for JSX elements.

Tidak, perubahan ini tidak benar. Anda tidak dapat mengembalikan beberapa elemen di React saat ini. Bahkan jika Anda melakukannya di suatu tempat, kemungkinan besar itu dienkapsulasi dalam satu cara.
Hanya di React 16 dengan Fiber ini mungkin :)

tidak yakin apakah mereka mengubah perilaku reaksi, tetapi penulis redux/react memamerkan kemampuan untuk mengembalikan this.props.children untuk membuat pembungkus tipis (hanya untuk menambahkan childContext ke elemen), seperti yang terlihat di https://egghead.io/lessons/ javascript-redux-passing-the-store-down-implicitly-via-context

react-native memungkinkan Anda untuk mengembalikan array elemen JSX dari render. solusinya adalah membungkus this.props.children dengan React.Children.only(this.props.children) dan itu akan dibuang jika ada lebih dari satu elemen sebagai root

Benar, Anda dapat menggunakan React.Children.only tetapi keduanya ReactNode DAN ReactElement adalah nilai yang valid dari this.props.children .

const Title = props => <h1>{props.children}</h1>;
<Title>Woah</Title>

adalah kode React yang valid dan masuk akal.

Anda dapat mengembalikan array elemen dalam reaksi 16, tetapi TS membuat kesalahan karena menganggap Anda tidak bisa.

Sunting: lakukan ini children: JSX.Element[]; untuk memperbaikinya

Dari pengalaman saya sejauh ini, sepertinya ReactNode harus valid.

const Id: React.SFC<{}> = (props) => props.children

const App = ()= > <Id>This should work but instead fails</Id>

Apakah ada kemungkinan ini akan tercermin dalam @types/react ?

Tanpa ini saya tidak dapat mengetik React children

Saat ini saya membungkus children dalam React.Fragment untuk menyiasatinya.

Ada pembaruan di dalamnya?

Tidak yakin apakah ini lebih atau kurang benar daripada membungkus children dalam React.Fragment , tetapi saya beruntung melakukannya

return (children as React.ReactElement);

return <>{foo(}</>; sepanjang malam. <> adalah solusi.

Ini menyebabkan masalah bagi saya juga.

TL; DR:

Saya memiliki HOC yang menambahkan alat peraga ke komponen tertentu, dan saya mencoba menggunakannya dengan komponen fungsional yang memiliki return children; . Ini hanya berfungsi jika saya menggunakan solusi return <>{children}</>; .

Keterangan lebih lanjut:

Berikut adalah versi sederhana dari HOC:

export interface ExtraProps {
  extraProp1: string;
}

export const withExtraProps = <P extends object>(Component: React.ComponentType<P>) => {
  return class extends React.Component<Omit<P, keyof ExtraProps>> {
    render() {
      const extraProps = {
        extraProp1: 'test'
      };

      return (
        <Component {...this.props as P} {...extraProps} />
      )
    }
  }
}

Berikut adalah versi sederhana dari komponen fungsional:

interface ComponentProps extends ExtraProps {
  children?: React.ReactNode;
  loadingComponent?: ReactElement;
}

export function ExampleComponent(props: ComponentProps) {
  const { children, loadingComponent } = props;

  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      await someAsyncCall();
      setLoading(false);
    }

    fetchData();
  });

  if (loading) {
    return loadingComponent || null;
  }

  return children;
}

// This line errors:
export const FeatureFlag = withExtraProps(ExampleComponent);

Saya mendapatkan kesalahan berikut:

Argument of type '(props: ComponentProps) => {} | null | undefined' is not assignable to parameter of type 'ComponentType<ComponentProps>'.
  Type '(props: ComponentProps) => {} | null | undefined' is not assignable to type 'FunctionComponent<ComponentProps>'.
    Type '{} | null | undefined' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.
      Type 'undefined' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.

Jika saya menambahkan tipe pengembalian ReactElement | null ke ExampleComponent, ia berhenti mengeluh tentang meneruskannya ke HOC, tetapi masih error saat saya mengembalikan anak-anak:

export function ExampleComponent(props: ComponentProps): ReactElement | null {
  ...
  ...
  return children; // Type 'ReactNode' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.

}

Seperti yang lain di sini, jika saya mengubahnya menjadi return <>{children}</>; , itu berfungsi, tetapi terasa kotor dan tidak perlu.

Saya memiliki _exact_ masalah yang sama dengan @kyrstenkelly - Fungsi HOC diteruskan React.FC yang menjadikannya anak-anak.

Perbaikan <> children(...) </> berfungsi, tetapi apakah ada solusi yang lebih baik?

Juga mengalami masalah ini! Saat ini sedang melakukan solusi yang disarankan untuk solusi pembungkus dengan React.Fragment

Sama disini

interface IIntlMessageProps {
    id: string;
    valuesGiven?: {[key:string]:string};
}

// this doesn't work - -- TS2769 Type 'null' is not assignable to type '(nodes:ReactNodeARray) => ReactNode' | ... | undefined
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
    return (
        <FormattedMessage id={props.id} values={props.valuesGiven}>
            {props.children}
        </FormattedMessage>
    )
};
//Nope -- TS2769 Type 'Element' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
    return (
        <FormattedMessage id={props.id} values={props.valuesGiven}>
            <React.Fragment>{props.children}</React.Fragment>
        </FormattedMessage>
    )
};

// Nope -- TS2769 Type 'Element' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> | null = (props) => {
    return (
        <FormattedMessage id={props.id} values={props.valuesGiven}>
            <>{props.children}</>
        </FormattedMessage>
    )
};

// Nope -- TS2769 Type '{}' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
    return (
        <FormattedMessage id={props.id} values={props.valuesGiven}>
            {props.children ? props.children : undefined}
        </FormattedMessage>
    )
};


Saya percaya saya telah mencoba semua yang disarankan di sini ... :( Ada petunjuk?

Solusinya adalah Anda perlu membungkusnya dalam fragmen.

import React from 'react'

const Something: React.FC = ({ children }) => (
 <> { children } </>
)

ini akan memperbaiki kesalahan Type '({ children }: { children?: ReactNode; }) => ReactNode' is not assignable to type 'FunctionComponent .

Jika memungkinkan, saya ingin menghindari fragmen dan membuat sistem tipe JSX mendukung jenis konstruksi yang sama yang didukung JavaScript dan Flow React, yang membantu TypeScript bekerja lebih baik dengan pola perpustakaan pihak ketiga.

Non-ideal lain yang saya temukan adalah bahwa fragmen memperdalam pohon komponen, terutama dalam komponen utilitas/pembungkus (case-in-point: react-placeholder). Mentransmisi ke React.ReactElement sepertinya merupakan pendekatan yang lebih baik di perpustakaan semacam ini, tetapi saya lebih suka tidak perlu melakukan casting.

Saya mencoba pendekatan untuk mengubah tipe itu, tetapi macet dengan pemeriksaan tipe JSX menggunakan komponen fungsional tipe baru. Saya masih memiliki cabang, bisa bersumpah saya membuat PR meminta bantuan, tidak dapat menemukannya kembali ...

Oke, jika tipe perlu melarang array node, itu tidak berarti bahwa itu harus melarang ReactText , ReactPortal , boolean , null , dan undefined juga apa kegunaan ReactElement .

Apa alasan untuk melarang jenis tambahan ini?

Apakah halaman ini membantu?
0 / 5 - 0 peringkat