Skip to content

Commit f410bc1

Browse files
Move defaultProps into preact/compat (#4657)
* Move `defaultProps` into `preact/compat` This will be handled in `options.vnode` for function/class components. This hook gets called for every invocation of `jsx`/`createElement` and `cloneElement`. * Try it * refactor: This is horrific but seems to work? (#4662) --------- Co-authored-by: Ryan Christian <[email protected]>
1 parent 78354fc commit f410bc1

File tree

14 files changed

+264
-227
lines changed

14 files changed

+264
-227
lines changed

compat/src/index.d.ts

Lines changed: 159 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,114 @@
11
import * as _hooks from '../../hooks';
22
// Intentionally not using a relative path to take advantage of
33
// the TS version resolution mechanism
4-
import * as preact from 'preact';
4+
import * as preact1 from 'preact';
55
import { JSXInternal } from '../../src/jsx';
66
import * as _Suspense from './suspense';
77

8+
<<<<<<< HEAD
9+
=======
10+
interface SignalLike<T> {
11+
value: T;
12+
peek(): T;
13+
subscribe(fn: (value: T) => void): () => void;
14+
}
15+
16+
type Signalish<T> = T | SignalLike<T>;
17+
18+
declare namespace preact {
19+
export interface FunctionComponent<P = {}> {
20+
(
21+
props: preact1.RenderableProps<P>,
22+
context?: any
23+
): preact1.ComponentChildren;
24+
displayName?: string;
25+
defaultProps?: Partial<P> | undefined;
26+
}
27+
28+
export interface ComponentClass<P = {}, S = {}> {
29+
new (props: P, context?: any): preact1.Component<P, S>;
30+
displayName?: string;
31+
defaultProps?: Partial<P>;
32+
contextType?: preact1.Context<any>;
33+
getDerivedStateFromProps?(
34+
props: Readonly<P>,
35+
state: Readonly<S>
36+
): Partial<S> | null;
37+
getDerivedStateFromError?(error: any): Partial<S> | null;
38+
}
39+
40+
export interface Component<P = {}, S = {}> {
41+
componentWillMount?(): void;
42+
componentDidMount?(): void;
43+
componentWillUnmount?(): void;
44+
getChildContext?(): object;
45+
componentWillReceiveProps?(nextProps: Readonly<P>, nextContext: any): void;
46+
shouldComponentUpdate?(
47+
nextProps: Readonly<P>,
48+
nextState: Readonly<S>,
49+
nextContext: any
50+
): boolean;
51+
componentWillUpdate?(
52+
nextProps: Readonly<P>,
53+
nextState: Readonly<S>,
54+
nextContext: any
55+
): void;
56+
getSnapshotBeforeUpdate?(oldProps: Readonly<P>, oldState: Readonly<S>): any;
57+
componentDidUpdate?(
58+
previousProps: Readonly<P>,
59+
previousState: Readonly<S>,
60+
snapshot: any
61+
): void;
62+
componentDidCatch?(error: any, errorInfo: preact1.ErrorInfo): void;
63+
}
64+
65+
export abstract class Component<P, S> {
66+
constructor(props?: P, context?: any);
67+
68+
static displayName?: string;
69+
static defaultProps?: any;
70+
static contextType?: preact1.Context<any>;
71+
72+
// Static members cannot reference class type parameters. This is not
73+
// supported in TypeScript. Reusing the same type arguments from `Component`
74+
// will lead to an impossible state where one cannot satisfy the type
75+
// constraint under no circumstances, see #1356.In general type arguments
76+
// seem to be a bit buggy and not supported well at the time of this
77+
// writing with TS 3.3.3333.
78+
static getDerivedStateFromProps?(
79+
props: Readonly<object>,
80+
state: Readonly<object>
81+
): object | null;
82+
static getDerivedStateFromError?(error: any): object | null;
83+
84+
state: Readonly<S>;
85+
props: preact1.RenderableProps<P>;
86+
context: any;
87+
88+
// From https://github.com/DefinitelyTyped/DefinitelyTyped/blob/e836acc75a78cf0655b5dfdbe81d69fdd4d8a252/types/react/index.d.ts#L402
89+
// // We MUST keep setState() as a unified signature because it allows proper checking of the method return type.
90+
// // See: https://github.com/DefinitelyTyped/DefinitelyTyped/issues/18365#issuecomment-351013257
91+
setState<K extends keyof S>(
92+
state:
93+
| ((
94+
prevState: Readonly<S>,
95+
props: Readonly<P>
96+
) => Pick<S, K> | Partial<S> | null)
97+
| (Pick<S, K> | Partial<S> | null),
98+
callback?: () => void
99+
): void;
100+
101+
forceUpdate(callback?: () => void): void;
102+
103+
abstract render(
104+
props?: preact1.RenderableProps<P>,
105+
state?: Readonly<S>,
106+
context?: any
107+
): preact1.ComponentChildren;
108+
}
109+
}
110+
111+
>>>>>>> Move `defaultProps` into `preact/compat` (#4657)
8112
// export default React;
9113
export = React;
10114
export as namespace React;
@@ -41,32 +145,32 @@ declare namespace React {
41145
): T;
42146

43147
// Preact Defaults
44-
export import Context = preact.Context;
45-
export import ContextType = preact.ContextType;
46-
export import RefObject = preact.RefObject;
148+
export import Context = preact1.Context;
149+
export import ContextType = preact1.ContextType;
150+
export import RefObject = preact1.RefObject;
47151
export import Component = preact.Component;
48152
export import FunctionComponent = preact.FunctionComponent;
49-
export import ComponentType = preact.ComponentType;
153+
export import ComponentType = preact1.ComponentType;
50154
export import ComponentClass = preact.ComponentClass;
51-
export import FC = preact.FunctionComponent;
52-
export import createContext = preact.createContext;
53-
export import Ref = preact.Ref;
54-
export import createRef = preact.createRef;
55-
export import Fragment = preact.Fragment;
56-
export import createElement = preact.createElement;
57-
export import cloneElement = preact.cloneElement;
58-
export import ComponentProps = preact.ComponentProps;
59-
export import ReactNode = preact.ComponentChild;
60-
export import ReactElement = preact.VNode;
61-
export import Consumer = preact.Consumer;
62-
export import ErrorInfo = preact.ErrorInfo;
155+
export import FC = preact1.FunctionComponent;
156+
export import createContext = preact1.createContext;
157+
export import Ref = preact1.Ref;
158+
export import createRef = preact1.createRef;
159+
export import Fragment = preact1.Fragment;
160+
export import createElement = preact1.createElement;
161+
export import cloneElement = preact1.cloneElement;
162+
export import ComponentProps = preact1.ComponentProps;
163+
export import ReactNode = preact1.ComponentChild;
164+
export import ReactElement = preact1.VNode;
165+
export import Consumer = preact1.Consumer;
166+
export import ErrorInfo = preact1.ErrorInfo;
63167

64168
// Suspense
65169
export import Suspense = _Suspense.Suspense;
66170
export import lazy = _Suspense.lazy;
67171

68172
// Compat
69-
export import StrictMode = preact.Fragment;
173+
export import StrictMode = preact1.Fragment;
70174
export const version: string;
71175
export function startTransition(cb: () => void): void;
72176

@@ -75,15 +179,15 @@ declare namespace React {
75179
extends JSXInternal.HTMLAttributes<T> {}
76180
export interface HTMLProps<T extends EventTarget>
77181
extends JSXInternal.AllHTMLAttributes<T>,
78-
preact.ClassAttributes<T> {}
182+
preact1.ClassAttributes<T> {}
79183
export interface AllHTMLAttributes<T extends EventTarget>
80184
extends JSXInternal.AllHTMLAttributes<T> {}
81185
export import DetailedHTMLProps = JSXInternal.DetailedHTMLProps;
82186
export import CSSProperties = JSXInternal.CSSProperties;
83187

84188
export interface SVGProps<T extends EventTarget>
85189
extends JSXInternal.SVGAttributes<T>,
86-
preact.ClassAttributes<T> {}
190+
preact1.ClassAttributes<T> {}
87191

88192
interface SVGAttributes extends JSXInternal.SVGAttributes {}
89193

@@ -181,73 +285,73 @@ declare namespace React {
181285
export import TransitionEventHandler = JSXInternal.TransitionEventHandler;
182286

183287
export function createPortal(
184-
vnode: preact.ComponentChildren,
185-
container: preact.ContainerNode
186-
): preact.VNode<any>;
288+
vnode: preact1.ComponentChildren,
289+
container: preact1.ContainerNode
290+
): preact1.VNode<any>;
187291

188292
export function render(
189-
vnode: preact.ComponentChild,
190-
parent: preact.ContainerNode,
293+
vnode: preact1.ComponentChild,
294+
parent: preact1.ContainerNode,
191295
callback?: () => void
192296
): Component | null;
193297

194298
export function hydrate(
195-
vnode: preact.ComponentChild,
196-
parent: preact.ContainerNode,
299+
vnode: preact1.ComponentChild,
300+
parent: preact1.ContainerNode,
197301
callback?: () => void
198302
): Component | null;
199303

200304
export function unmountComponentAtNode(
201-
container: preact.ContainerNode
305+
container: preact1.ContainerNode
202306
): boolean;
203307

204308
export function createFactory(
205-
type: preact.VNode<any>['type']
309+
type: preact1.VNode<any>['type']
206310
): (
207311
props?: any,
208-
...children: preact.ComponentChildren[]
209-
) => preact.VNode<any>;
312+
...children: preact1.ComponentChildren[]
313+
) => preact1.VNode<any>;
210314
export function isValidElement(element: any): boolean;
211315
export function isFragment(element: any): boolean;
212316
export function isMemo(element: any): boolean;
213317
export function findDOMNode(
214-
component: preact.Component | Element
318+
component: preact1.Component | Element
215319
): Element | null;
216320

217321
export abstract class PureComponent<
218322
P = {},
219323
S = {},
220324
SS = any
221-
> extends preact.Component<P, S> {
325+
> extends preact1.Component<P, S> {
222326
isPureReactComponent: boolean;
223327
}
224328

225-
export type MemoExoticComponent<C extends preact.FunctionalComponent<any>> =
226-
preact.FunctionComponent<ComponentProps<C>> & {
329+
export type MemoExoticComponent<C extends preact1.FunctionalComponent<any>> =
330+
preact1.FunctionComponent<ComponentProps<C>> & {
227331
readonly type: C;
228332
};
229333

230334
export function memo<P = {}>(
231-
component: preact.FunctionalComponent<P>,
335+
component: preact1.FunctionalComponent<P>,
232336
comparer?: (prev: P, next: P) => boolean
233-
): preact.FunctionComponent<P>;
234-
export function memo<C extends preact.FunctionalComponent<any>>(
337+
): preact1.FunctionComponent<P>;
338+
export function memo<C extends preact1.FunctionalComponent<any>>(
235339
component: C,
236340
comparer?: (
237-
prev: preact.ComponentProps<C>,
238-
next: preact.ComponentProps<C>
341+
prev: preact1.ComponentProps<C>,
342+
next: preact1.ComponentProps<C>
239343
) => boolean
240344
): C;
241345

242-
export interface RefAttributes<R> extends preact.Attributes {
243-
ref?: preact.Ref<R> | undefined;
346+
export interface RefAttributes<R> extends preact1.Attributes {
347+
ref?: preact1.Ref<R> | undefined;
244348
}
245349

246350
/**
247351
* @deprecated Please use `ForwardRefRenderFunction` instead.
248352
*/
249353
export interface ForwardFn<P = {}, T = any> {
250-
(props: P, ref: ForwardedRef<T>): preact.ComponentChild;
354+
(props: P, ref: ForwardedRef<T>): preact1.ComponentChild;
251355
displayName?: string;
252356
}
253357

@@ -257,13 +361,18 @@ declare namespace React {
257361
}
258362

259363
export interface ForwardRefExoticComponent<P>
260-
extends preact.FunctionComponent<P> {
364+
extends preact1.FunctionComponent<P> {
261365
defaultProps?: Partial<P> | undefined;
262366
}
263367

264368
export function forwardRef<R, P = {}>(
369+
<<<<<<< HEAD
265370
fn: ForwardRefRenderFunction<R, P>
266371
): preact.FunctionalComponent<PropsWithoutRef<P> & { ref?: preact.Ref<R> }>;
372+
=======
373+
fn: ForwardFn<P, R>
374+
): preact1.FunctionalComponent<PropsWithoutRef<P> & { ref?: preact1.Ref<R> }>;
375+
>>>>>>> Move `defaultProps` into `preact/compat` (#4657)
267376

268377
export type PropsWithoutRef<P> = Omit<P, 'ref'>;
269378

@@ -311,21 +420,21 @@ declare namespace React {
311420
export function flushSync<A, R>(fn: (a: A) => R, a: A): R;
312421

313422
export type PropsWithChildren<P = unknown> = P & {
314-
children?: preact.ComponentChildren | undefined;
423+
children?: preact1.ComponentChildren | undefined;
315424
};
316425

317426
export const Children: {
318-
map<T extends preact.ComponentChild, R>(
427+
map<T extends preact1.ComponentChild, R>(
319428
children: T | T[],
320429
fn: (child: T, i: number) => R
321430
): R[];
322-
forEach<T extends preact.ComponentChild>(
431+
forEach<T extends preact1.ComponentChild>(
323432
children: T | T[],
324433
fn: (child: T, i: number) => void
325434
): void;
326-
count: (children: preact.ComponentChildren) => number;
327-
only: (children: preact.ComponentChildren) => preact.ComponentChild;
328-
toArray: (children: preact.ComponentChildren) => preact.VNode<{}>[];
435+
count: (children: preact1.ComponentChildren) => number;
436+
only: (children: preact1.ComponentChildren) => preact1.ComponentChild;
437+
toArray: (children: preact1.ComponentChildren) => preact1.VNode<{}>[];
329438
};
330439

331440
// scheduler

compat/src/render.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
useSyncExternalStore,
2525
useTransition
2626
} from './index';
27+
import { assign } from './util';
2728

2829
export const REACT_ELEMENT_TYPE = Symbol.for('react.element');
2930

@@ -237,8 +238,15 @@ options.vnode = vnode => {
237238
// only normalize props on Element nodes
238239
if (typeof vnode.type === 'string') {
239240
handleDomVNode(vnode);
241+
} else if (typeof vnode.type === 'function' && vnode.type.defaultProps) {
242+
let normalizedProps = assign({}, vnode.props);
243+
for (let i in vnode.type.defaultProps) {
244+
if (normalizedProps[i] === undefined) {
245+
normalizedProps[i] = vnode.type.defaultProps[i];
246+
}
247+
}
248+
vnode.props = normalizedProps;
240249
}
241-
242250
vnode.$$typeof = REACT_ELEMENT_TYPE;
243251

244252
if (oldVNodeHook) oldVNodeHook(vnode);

0 commit comments

Comments
 (0)