类型错误:JSX元素类型'{} |空| undefined'不是JSX元素的构造函数

时间:2019-02-27 12:20:42

标签: reactjs typescript react-apollo

我有一个名为HandleQuery的React组件,用于处理Apollo GraphQL查询的结果:

import React, { ReactNode } from 'react';

import { CenteredMessage } from './centered-message';

export interface HandleQueryProps {
    loading: boolean,
    error?: Error,
    children: ReactNode
}

export const HandleQuery = ({ loading, error, children }: HandleQueryProps) => {
    if (loading) {
        return <CenteredMessage>Loading...</CenteredMessage>;
    }

    if (error) {
        return <CenteredMessage>{error.message}</CenteredMessage>;
    }

    return children;
};

在另一个组件中使用此组件时,它不会编译:

import React from 'react';

import { useQuery } from 'react-apollo-hooks';
import gql from 'graphql-tag';
import { HandleQuery } from '..';
import { MutationType } from '../../graphql-types';
import { AuthorsPanel } from './authors-panel';
import { GET_AUTHORS } from './authors-queries';
import { AuthorMutated } from './__generated__/AuthorMutated';

export class AuthorsContainer extends React.Component {
    render() {
        const { loading, error, data } = useQuery(GET_AUTHORS);
        return (
            <!-- THIS LINE PRODUCES A COMPILER ERROR -->
            <HandleQuery loading={loading} error={error}>
                <AuthorsPanel data={data} />
            </HandleQuery>
        );
    }
}

在上面使用HandleQuery会产生以下错误:

  

类型错误:JSX元素类型'{} |空| undefined'不是JSX元素的构造函数。     类型'undefined'不能分配给类型'Element |空值'。 TS2605

这是什么意思,我该如何摆脱呢?

更新

将AuthorsContainer转换为功能组件并不能消除错误:

export const AuthorsContainer = () => {
    const { loading, error, data } = useQuery(GET_AUTHORS);
    return (
        <HandleQuery loading={loading} error={error}>
            <AuthorsPanel data={data} />
        </HandleQuery>
    );
};

更新2 实施@FredyC的建议:

import React from 'react';

import { CenteredMessage } from './centered-message';

export interface HandleQueryProps {
    loading: boolean;
    error?: Error;
}

export const HandleQuery: React.FC<HandleQueryProps> = ({
    loading,
    error,
    children
}) => {
    if (loading) {
        return <CenteredMessage>Loading...</CenteredMessage>;
    }

    if (error) {
        return <CenteredMessage>{error.message}</CenteredMessage>;
    }

    return children;
};

现在,容器组件上的错误已消失,但是HandleQuery组件上弹出了一个新的编译器错误:

Type error: Type '({ loading, error, children }: PropsWithChildren<HandleQueryProps>) => {} | null | undefined' is not assignable to type 'FunctionComponent<HandleQueryProps>'.
  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'.  TS2322

4 个答案:

答案 0 :(得分:2)

关于ReactNode长期存在问题。我不了解具体细节,但这是TypeScript本身的硬连线,正在研究中。

无论哪种方式,解决方案都应该很容易。不要将ReactNode与功能组件一起使用:) children属性隐式包含在React.FC类型中。

返回的孩子也有同样的问题。如果愿意,可以通过包装为<React.Fragment><div>来克服它,但是由于它只是类型错误,因此您可以说服TypeScript您知道自己在做什么:)

import React, { ReactNode } from 'react';

import { CenteredMessage } from './centered-message';

export interface HandleQueryProps {
    loading: boolean,
    error?: Error,
}

export const HandleQuery: React.FC<HandleQueryProps> = ({ loading, error, children }) => {
    if (loading) {
        return <CenteredMessage>Loading...</CenteredMessage>;
    }

    if (error) {
        return <CenteredMessage>{error.message}</CenteredMessage>;
    }

    return children as ReactElement<any>;
};

答案 1 :(得分:0)

在这种情况下,如果我不排除某些问题,只需定义类型为children的{​​{1}}会更容易。

ReactElement

答案 2 :(得分:0)

ReactNode 切换为 JSX.Element 解决了类型问题。

根据the related github issue on React,建议对功能组件使用JSX.Element而不是ReactNode

您可以在typescript-cheatsheets/react page中查看JSX.ElementReactNode的详细信息。

答案 3 :(得分:-1)

对我来说,此命令解决了问题:

rm -rf node_modules && rm yarn.lock && yarn