Flow: React RestrictedElement
· 2 min read
RestrictedElement<typeof MenuItem>
export type RestrictedElement<+TElementType: React$ElementType> = {|
+type:
| TElementType
| ClassComponentRender<RestrictedElement<TElementType>>
| FunctionComponentRender<RestrictedElement<TElementType>>,
+props: any, // The props type is already captured in the type field,
// and using ElementProps recursively can get very expensive. Instead
// of paying for that computation, I decided to use any
+key: React$Key | null,
+ref: any,
|};
flow.org/try, alternative to: https://flow.org/en/docs/react/children/#toc-only-allowing-a-specific-element-type-as-children
The one recommended in the docs is just for children with exactly that type. RestrictedElement
lets you also use things that render things of that type. So suppose you have some Button class. Let's say the button has a disabled flag. You might want to make another class:
class DisabledButton {
render(): React.Element<typeof Button> { ... }
}
You can't use DisabledButton
inside a children array for React.Element<typeof Button>
but you can in RestrictedElement<typeof Button>
. (via @jbrown215)
Real example:
// @flow
import * as React from 'react';
import { type RestrictedElement } from './RestrictedElement';
class Button extends React.Component<{| +disabled?: boolean |}> {
render() {
return null;
}
}
class DisabledButton extends React.Component<{||}> {
// The return type is not necessary - it's here only to demonstrate what is going on.
render(): React.Element<typeof Button> {
return <Button disabled={true} />;
}
}
class WrapperStupid extends React.Component<{|
children: React.ChildrenArray<
// You have to specify every single supported component here.
React.Element<typeof Button> | React.Element<typeof DisabledButton>,
>,
|}> {}
class WrapperSmart extends React.Component<{|
// Type `RestrictedElement` understands what is being rendered so it accepts even `DisabledButton` (because it returns `Button`).
children: React.ChildrenArray<RestrictedElement<typeof Button>>,
|}> {}
const testStupid = (
<WrapperStupid>
<Button />
<Button />
<DisabledButton />
</WrapperStupid>
);
const testSmart = (
<WrapperSmart>
<Button />
<Button />
<DisabledButton />
</WrapperSmart>
);