Skip to content

Commit 71f8531

Browse files
committed
Slot: Strengthen type checking for lazy components
1 parent 17b6b35 commit 71f8531

File tree

1 file changed

+18
-7
lines changed

1 file changed

+18
-7
lines changed

packages/react/slot/src/slot.tsx

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,28 +11,39 @@ const REACT_LAZY_TYPE = Symbol.for('react.lazy');
1111

1212
interface LazyReactElement extends React.ReactElement {
1313
$$typeof: typeof REACT_LAZY_TYPE;
14-
_payload: any;
14+
_payload: PromiseLike<Exclude<React.ReactNode, PromiseLike<any>>>;
1515
}
1616

1717
/* -------------------------------------------------------------------------------------------------
1818
* Slot
1919
* -----------------------------------------------------------------------------------------------*/
2020

21+
export type Usable<T> = PromiseLike<T> | React.Context<T>;
22+
const use: typeof React.use | undefined = (React as any)[' use '.trim().toString()];
23+
2124
interface SlotProps extends React.HTMLAttributes<HTMLElement> {
2225
children?: React.ReactNode;
2326
}
2427

28+
function isPromiseLike(value: unknown): value is PromiseLike<unknown> {
29+
return typeof value === 'object' && value !== null && 'then' in value;
30+
}
31+
2532
function isLazyComponent(element: React.ReactNode): element is LazyReactElement {
26-
// has to be done in a roundabout way unless we want to add a dependency on react-is
27-
return React.isValidElement(element) && element.$$typeof === REACT_LAZY_TYPE;
33+
return (
34+
React.isValidElement(element) &&
35+
element.$$typeof === REACT_LAZY_TYPE &&
36+
'_payload' in element &&
37+
isPromiseLike(element._payload)
38+
);
2839
}
2940

3041
/* @__NO_SIDE_EFFECTS__ */ export function createSlot(ownerName: string) {
3142
const SlotClone = createSlotClone(ownerName);
3243
const Slot = React.forwardRef<HTMLElement, SlotProps>((props, forwardedRef) => {
3344
let { children, ...slotProps } = props;
34-
if (isLazyComponent(children)) {
35-
children = React.use(children._payload);
45+
if (isLazyComponent(children) && typeof use === 'function') {
46+
children = use(children._payload);
3647
}
3748
const childrenArray = React.Children.toArray(children);
3849
const slottable = childrenArray.find(isSlottable);
@@ -87,8 +98,8 @@ interface SlotCloneProps {
8798
/* @__NO_SIDE_EFFECTS__ */ function createSlotClone(ownerName: string) {
8899
const SlotClone = React.forwardRef<any, SlotCloneProps>((props, forwardedRef) => {
89100
let { children, ...slotProps } = props;
90-
if (isLazyComponent(children)) {
91-
children = React.use(children._payload);
101+
if (isLazyComponent(children) && typeof use === 'function') {
102+
children = use(children._payload);
92103
}
93104

94105
if (React.isValidElement(children)) {

0 commit comments

Comments
 (0)