Skip to content

Instantly share code, notes, and snippets.

@atabel
Created February 4, 2022 16:23
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save atabel/badefe5d16ad77d5310d58c4be3f2c6a to your computer and use it in GitHub Desktop.
Save atabel/badefe5d16ad77d5310d58c4be3f2c6a to your computer and use it in GitHub Desktop.
Recursive React.Element
// @flow
import * as React from 'react';
type RendersElement<+TElementType: React.ElementType> = {
+type: TElementType | ((props: any) => RendersElement<TElementType>),
+props: any,
+key: React.Key | null,
+ref: any,
};
type ItemProps = {foo: string};
export const Item = (props: ItemProps): React.Node => <div>{props.foo}</div>;
type Item2Props = {bar: string};
export const Item2 = (props: Item2Props): React.Element<typeof Item> => <Item foo={props.bar} />;
type Item3Props = {zoo: string};
export const Item3 = (props: Item3Props): React.Element<typeof Item2> => <Item2 bar={props.zoo} />;
type NotItemProps = {a: string};
export const NotItem = (props: NotItemProps): React.Node => props.a;
type Renders<+T: React$ElementType> = React$Element<T | ((props: any) => Renders<T>)>;
type Props = {
item: RendersElement<typeof Item>,
};
export const Component = (props: Props): React.Node => <div>{props.item}</div>;
export const Test = (): React.Node => <Component item={<Item foo="bar" />} />;
export const Test2 = (): React.Node => <Component item={<Item2 bar="bar" />} />; // works because Item2 renders Item
export const Test3 = (): React.Node => <Component item={<Item3 zoo="bar" />} />; // works because Item3 renders Item2, which renders Item
export const Test4 = (): React.Node => <Component item={<div />} />; // expected error because div isn't an Item element
export const Test5 = (): React.Node => <Component item={<NotItem a="" />} />; // expected error because NotItem doesn't end up rendering an Item
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment