Definitelytyped: Type of React.ReactFragment, which includes {}, breaks certain usages of children in TS 3.1

Created on 1 Oct 2018  路  4Comments  路  Source: DefinitelyTyped/DefinitelyTyped

  • [x] I tried using the @types/xxxx package and had problems.
  • [x] I tried using the latest stable version of tsc. https://www.npmjs.com/package/typescript
  • [x] I have a question that is inappropriate for StackOverflow. (Please ask any appropriate questions there).
  • [x] [Mention](https://github.com/blog/821-mention-somebody-they-re-notified) the authors (see Definitions by: in index.d.ts) so they can respond.

    • Authors: @johnnyreilly

    • (Note: it's really hard to mention any author since none of them have github tags in the index.d.ts)

The type of ReactFragment currently includes {}, which causes the new, safer handling of typeof x === 'function' to only narrow x to Function.

Sample playground link

This same code would work as intended in TS 3.0.

I don't know why an empty object is considered a valid fragment; this allows literally anything to be passed as a child as long as it's not "fresh".

Most helpful comment

This is big a problem. Because a React component can render a fragment, & because ReactFragment is such a loose type, this means you can literally return anything from a React component's render function. People can return invalid, unrenderable objects that blow up at run-time and get no warning or compiler error from TypeScript. This just seems wrong. Is there any way we can address this sooner?

All 4 comments

To fix this a major overhaul of types would be needed, which is not gonna happen anytime soon IMHO

What you can do in the meantime is to use ReactChild or ReactElement

which type is 馃憠 type ReactChild = ReactElement<any> | ReactText; and basically that's what you want.
I didn't came to a situation when my component had to accept boolean or empty ( null | defined ) value as children.

interface Props {
  children: React.ReactChild | () => React.ReactChild
}

or if you need to accept null undefined as well you can map those types via Maybe:

type Maybe<T> = T | null | undefined
interface Props {
  children: Maybe<React.ReactChild> | () => Maybe<React.ReactChild>
}

A related issue of ReactFragment accepting {} is that it's easy to misreference functions within React components instead of calling them. React DOM complains at runtime, but React Native doesn't which can make it hard to catch. Regardless of runtime handling, it would be great if we could get the types updated to support this.

<Text>{getText}</Text>   // oops!
<Text>{getText()}</Text> // fixed

TypeScript playground. Flow equivalent that catches this error.

This is big a problem. Because a React component can render a fragment, & because ReactFragment is such a loose type, this means you can literally return anything from a React component's render function. People can return invalid, unrenderable objects that blow up at run-time and get no warning or compiler error from TypeScript. This just seems wrong. Is there any way we can address this sooner?

What is preventing {} from being removed as a possibility? It just seems wrong and haphazard.

Was this page helpful?
0 / 5 - 0 ratings