Skip to content

Commit 3debe02

Browse files
Use type guards for internal types
1 parent ca2bee9 commit 3debe02

File tree

8 files changed

+86
-38
lines changed

8 files changed

+86
-38
lines changed

src/create-context.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ let nextContextId = 0;
44

55
const providers = new Set();
66

7-
/** @param {import('./internal').Internal} internal */
7+
/** @param {import('./internal').ComponentInternal} internal */
88
export const unsubscribeFromContext = internal => {
99
// if this was a context provider, delete() returns true and we exit:
1010
if (providers.delete(internal)) return;

src/diff/catch-error.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import {
22
DIRTY_BIT,
33
MODE_RERENDERING_ERROR,
4-
MODE_PENDING_ERROR,
5-
TYPE_COMPONENT
4+
MODE_PENDING_ERROR
65
} from '../constants';
76
import { ENABLE_CLASSES } from '../component';
7+
import { isComponentInternal } from '../helpers';
88

99
/**
1010
* Find the closest error boundary to a thrown error and call it
@@ -16,7 +16,7 @@ import { ENABLE_CLASSES } from '../component';
1616
export function _catchError(error, internal) {
1717
while ((internal = internal._parent)) {
1818
if (
19-
internal.flags & TYPE_COMPONENT &&
19+
isComponentInternal(internal) &&
2020
~internal.flags & MODE_RERENDERING_ERROR
2121
) {
2222
try {

src/diff/children.js

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
import { applyRef } from './refs';
22
import { normalizeToVNode } from '../create-element';
33
import {
4-
TYPE_COMPONENT,
54
MODE_HYDRATE,
65
MODE_SUSPENDED,
76
EMPTY_ARR,
8-
TYPE_DOM,
97
UNDEFINED
108
} from '../constants';
119
import { mount } from './mount';
1210
import { patch } from './patch';
1311
import { unmount } from './unmount';
1412
import { createInternal, getDomSibling } from '../tree';
13+
import { isComponentInternal, isDomInternal } from '../helpers';
1514

1615
/**
1716
* Update an internal with new children.
@@ -98,7 +97,7 @@ export function patchChildren(internal, children, parentDom) {
9897
}
9998

10099
// Perform insert of new dom
101-
if (childInternal.flags & TYPE_DOM) {
100+
if (isDomInternal(childInternal)) {
102101
parentDom.insertBefore(
103102
childInternal.data,
104103
getDomSibling(internal, skewedIndex)
@@ -132,7 +131,7 @@ export function patchChildren(internal, children, parentDom) {
132131
if (matchingIndex == i) break go;
133132

134133
let nextSibling = getDomSibling(internal, skewedIndex + 1);
135-
if (childInternal.flags & TYPE_DOM) {
134+
if (isDomInternal(childInternal)) {
136135
parentDom.insertBefore(childInternal.data, nextSibling);
137136
} else {
138137
insertComponentDom(childInternal, nextSibling, parentDom);
@@ -241,7 +240,7 @@ export function insertComponentDom(internal, nextSibling, parentDom) {
241240
if (childInternal) {
242241
childInternal._parent = internal;
243242

244-
if (childInternal.flags & TYPE_COMPONENT) {
243+
if (isComponentInternal(childInternal)) {
245244
insertComponentDom(childInternal, nextSibling, parentDom);
246245
} else if (childInternal.data != nextSibling) {
247246
parentDom.insertBefore(childInternal.data, nextSibling);

src/diff/mount.js

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { applyRef } from './refs';
22
import {
3-
TYPE_COMPONENT,
43
TYPE_ELEMENT,
54
MODE_HYDRATE,
65
MODE_MUTATIVE_HYDRATE,
@@ -9,7 +8,6 @@ import {
98
TYPE_TEXT,
109
TYPE_CLASS,
1110
MODE_ERRORED,
12-
TYPE_ROOT,
1311
MODE_SVG,
1412
DIRTY_BIT
1513
} from '../constants';
@@ -19,6 +17,7 @@ import { createInternal, getParentContext } from '../tree';
1917
import options from '../options';
2018
import { ENABLE_CLASSES } from '../component';
2119
import { commitQueue } from './commit';
20+
import { isComponentInternal, isRootInternal } from '../helpers';
2221
/**
2322
* Diff two virtual nodes and apply proper changes to the DOM
2423
* @param {import('../internal').Internal} internal The Internal node to mount
@@ -34,14 +33,11 @@ export function mount(internal, newVNode, parentDom, startDom) {
3433
let nextDomSibling, prevStartDom;
3534

3635
try {
37-
if (internal.flags & TYPE_COMPONENT) {
36+
if (isComponentInternal(internal)) {
3837
// Root nodes signal that an attempt to render into a specific DOM node on
3938
// the page. Root nodes can occur anywhere in the tree and not just at the
4039
// top.
41-
if (
42-
internal.flags & TYPE_ROOT &&
43-
newVNode.props._parentDom !== parentDom
44-
) {
40+
if (isRootInternal(internal) && newVNode.props._parentDom !== parentDom) {
4541
parentDom = newVNode.props._parentDom;
4642
prevStartDom = startDom;
4743
startDom = null;
@@ -59,6 +55,7 @@ export function mount(internal, newVNode, parentDom, startDom) {
5955
);
6056
}
6157

58+
//
6259
if (
6360
internal.data._commitCallbacks &&
6461
internal.data._commitCallbacks.length
@@ -249,7 +246,7 @@ export function mountChildren(internal, children, parentDom, startDom) {
249246

250247
newDom = childInternal.data;
251248

252-
if (childInternal.flags & TYPE_COMPONENT || newDom == startDom) {
249+
if (isComponentInternal(childInternal) || newDom == startDom) {
253250
// If the child is a Fragment-like or if it is DOM VNode and its _dom
254251
// property matches the dom we are diffing (i.e. startDom), just
255252
// continue with the mountedNextChild
@@ -290,14 +287,14 @@ export function mountChildren(internal, children, parentDom, startDom) {
290287
}
291288

292289
/**
293-
* @param {import('../internal').Internal} internal The component's backing Internal node
290+
* @param {import('../internal').ComponentInternal} internal The component's backing Internal node
294291
* @param {import('../internal').PreactNode} startDom the preceding node
295292
* @returns {import('../internal').PreactNode} the component's children
296293
*/
297294
function mountComponent(internal, startDom) {
298295
/** @type {import('../internal').Component} */
299296
let c;
300-
let type = /** @type {import('../internal').ComponentType} */ (internal.type);
297+
let type = internal.type;
301298
let newProps = internal.props;
302299

303300
// Necessary for createContext api. Setting this property will pass

src/diff/patch.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ function patchElement(internal, vnode) {
192192
}
193193

194194
/**
195-
* @param {import('../internal').Internal} internal The component's backing Internal node
195+
* @param {import('../internal').ComponentInternal} internal The component's backing Internal node
196196
* @param {import('../internal').VNode} newVNode The new virtual node
197197
* @returns {import('../internal').ComponentChildren} the component's children
198198
*/

src/helpers.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { TYPE_COMPONENT, TYPE_DOM, TYPE_ELEMENT, TYPE_ROOT } from './constants';
2+
3+
/** @type {import('./internal').isComponentInternal} */
4+
export const isComponentInternal = internal =>
5+
/** @type {*} */ (internal.flags & TYPE_COMPONENT);
6+
7+
/** @type {import('./internal').isDomInternal} */
8+
export const isDomInternal = internal =>
9+
/** @type {*} */ (internal.flags & TYPE_DOM);
10+
11+
/** @type {import('./internal').isRootInternal} */
12+
export const isRootInternal = internal =>
13+
/** @type {*} */ (internal.flags & TYPE_ROOT);
14+
15+
/** @type {(internal: import('./internal').Internal) => number} */
16+
export const isElementInternal = internal => internal.flags & TYPE_ELEMENT;

src/internal.d.ts

Lines changed: 42 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ export interface Options extends preact.Options {
4545
_internal?(internal: Internal, vnode: VNode | string): void;
4646
}
4747

48-
export type CommitQueue = Internal[];
48+
export type CommitQueue = ComponentInternal[];
4949

5050
// Redefine ComponentFactory using our new internal FunctionalComponent interface above
5151
export type ComponentFactory<P> =
@@ -130,18 +130,13 @@ export interface VNode<P = {}> extends preact.VNode<P> {
130130
* An Internal is a persistent backing node within Preact's virtual DOM tree.
131131
* Think of an Internal like a long-lived VNode with stored data and tree linkages.
132132
*/
133-
export interface Internal<P = {}> {
134-
type: string | ComponentType<P>;
135-
/** The props object for Elements/Components, and the string contents for Text */
136-
props: (P & { children: ComponentChildren }) | string | number;
133+
export interface BaseInternal<P = {}> {
137134
key: any;
138135
ref: Ref<any> | null;
139136
_prevRef: Ref<any> | null;
140137

141138
/** Bitfield containing information about the Internal or its component. */
142139
flags: number;
143-
/** Polymorphic property to store extensions like hooks on */
144-
data: object | PreactNode;
145140
/** The function that triggers in-place re-renders for an internal */
146141
rerender: (internal: Internal) => void;
147142

@@ -159,16 +154,52 @@ export interface Internal<P = {}> {
159154
_component: Component | null;
160155
/** This Internal's distance from the tree root */
161156
_depth: number | null;
162-
/** Callbacks to invoke when this internal commits */
163-
_commitCallbacks: Array<() => void>;
164-
_stateCallbacks: Array<() => void>; // Only class components
165157
}
166158

159+
export interface ComponentInternal<P = {}> extends BaseInternal<P> {
160+
type: ComponentType<P>;
161+
props: P & { children: ComponentChildren };
162+
/** Polymorphic property to store extensions like hooks on */
163+
data: {
164+
/** Callbacks to invoke when this internal commits */
165+
_commitCallbacks: Array<() => void>;
166+
_stateCallbacks: Array<() => void>; // Only class components
167+
[key: string]: any;
168+
};
169+
}
170+
171+
export interface RootInternal<P = {}>
172+
extends Exclude<ComponentInternal<P>, 'props'> {
173+
props: P & { children: ComponentChildren; _parentDom: PreactNode };
174+
}
175+
176+
export interface DomInternal<P = {}> extends BaseInternal<P> {
177+
type: string;
178+
/** The props object for Elements/Components, and the string contents for Text */
179+
props: (P & { children: ComponentChildren }) | string | number;
180+
data: PreactNode;
181+
}
182+
183+
export type Internal<P = {}> =
184+
| ComponentInternal<P>
185+
| DomInternal<P>
186+
| RootInternal<P>;
187+
188+
export type isDomInternal<P = {}> = (
189+
internal: Internal<P>
190+
) => internal is DomInternal<P>;
191+
export type isComponentInternal<P = {}> = (
192+
internal: Internal<P>
193+
) => internal is ComponentInternal<P>;
194+
export type isRootInternal<P = {}> = (
195+
internal: Internal<P>
196+
) => internal is RootInternal<P>;
197+
167198
export interface Component<P = {}, S = {}> extends preact.Component<P, S> {
168199
// When component is functional component, this is reset to functional component
169200
constructor: ComponentType<P>;
170201
state: S; // Override Component["state"] to not be readonly for internal use, specifically Hooks
171-
_internal?: Internal<P> | null;
202+
_internal?: ComponentInternal<P> | null;
172203
_nextState?: S | null; // Only class components
173204
/** Only used in the devtools to later dirty check if state has changed */
174205
_prevState?: S | null;

src/tree.js

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,16 @@ import {
77
TYPE_ROOT,
88
INHERITED_MODES,
99
TYPE_COMPONENT,
10-
TYPE_DOM,
1110
MODE_SVG,
1211
UNDEFINED
1312
} from './constants';
1413
import { enqueueRender } from './component';
14+
import {
15+
isComponentInternal,
16+
isDomInternal,
17+
isElementInternal,
18+
isRootInternal
19+
} from './helpers';
1520

1621
/**
1722
* Create an internal tree node
@@ -106,8 +111,8 @@ export function createInternal(vnode, parentInternal) {
106111
}
107112

108113
const shouldSearchComponent = internal =>
109-
internal.flags & TYPE_COMPONENT &&
110-
(!(internal.flags & TYPE_ROOT) ||
114+
isComponentInternal(internal) &&
115+
(!isRootInternal(internal) ||
111116
internal.props._parentDom == getParentDom(internal._parent));
112117

113118
/**
@@ -153,7 +158,7 @@ export function getChildDom(internal, offset) {
153158
for (; offset < internal._children.length; offset++) {
154159
let child = internal._children[offset];
155160
if (child != null) {
156-
if (child.flags & TYPE_DOM) {
161+
if (isDomInternal(child)) {
157162
return child.data;
158163
}
159164

@@ -190,15 +195,15 @@ export function getParentDom(internal) {
190195
let parent = internal;
191196

192197
// if this is a Root internal, return its parent DOM:
193-
if (parent.flags & TYPE_ROOT) {
198+
if (isRootInternal(parent)) {
194199
return parent.props._parentDom;
195200
}
196201

197202
// walk up the tree to find the nearest DOM or Root Internal:
198203
while ((parent = parent._parent)) {
199-
if (parent.flags & TYPE_ROOT) {
204+
if (isRootInternal(parent)) {
200205
return parent.props._parentDom;
201-
} else if (parent.flags & TYPE_ELEMENT) {
206+
} else if (isElementInternal(parent)) {
202207
return parent.data;
203208
}
204209
}

0 commit comments

Comments
 (0)