Потому что тип React.ReactNode
- это тип объединения. Давайте посмотрим, как выглядит определение типа для него:
type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;
Ожидаемый тип возврата при создании функционального компонента с generi c FC
ReactElement<any, any> | null
Итак, когда вы возвращаете children
непосредственно из компонента, компилятор жалуется, потому что типы просто несовместимы. Причина в том, что ReactElement
является действительным React.ReactNode
, но не наоборот, потому что React.ReactNode
также может быть значением типа ReactFragment
или ReactPortal
и т. Д.
Это очевидно что это создаст несоответствие типов с ReactElement
. Но когда вы возвращаете children
внутри Fragment
, компилятор больше не жалуется, потому что возвращаемый тип становится действительным. Взгляните на этот пример без FC
generi c,
// The return type of Foo is inferred as React.ReactNode
// Compiler doesn't complain because we don't annotate the return type
const Foo = ({ children }: PropsWithChildren<FooProps>) => {
return children;
};
// But when you use React.FC generic it is the same as annotating the return type
// of Foo as `React.ReactElement`
// compiler will complain because of the type mismatch
const Foo = ({ children }: PropsWithChildren<FooProps>): React.ReactElement => {
return children;
};
Пример того, почему это работает, когда вы возвращаете children
внутри Fragment
// Without generic FC
// Return type infered as JSX.Element which simply extends React.ReactElement
const Foo = ({ children }: PropsWithChildren<FooProps>) => {
return <>children</>;
};
// With generic FC
// Compiler doesn't complain because of JSX.Element can be valid-
// return type because it simply extends the interface React.ReactElement
const Foo: FC<FooProps> = ({ children }) => {
return <>children</>;
};
Изменить - Возможно, это не прямой ответ, но я надеюсь, что этот пример может больше объяснить, почему React.ReactNode
нельзя разрешать.
React.ReactNode
является широким, и вы можете назначить ему практически что угодно. Например,
const Foo = () => { return 45; };
// no compile time error because even a functions are a valid ReactNode
const Bar: React.ReactNode = Foo
Но что происходит, когда мы пытаемся отобразить его внутри любого допустимого компонента
Во время компиляции - Нет ошибки
const FooBar: React.FC<FooProps> = () => {
// again no compile time error because Bar is a valid ReactNode
return <div>{Bar}</div>
}
Во время выполнения - Функции ошибок недопустимы, реагировать на дочерние элементы