Skip to content

Commit fa83cd8

Browse files
authored
chore: Add some types to router, rename a couple vars (#32)
1 parent 1337db0 commit fa83cd8

File tree

4 files changed

+45
-17
lines changed

4 files changed

+45
-17
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
},
2222
"files": [
2323
"src",
24+
"!src/internal.d.ts",
2425
"LICENSE",
2526
"package.json",
2627
"README.md"

src/internal.d.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
export interface AugmentedComponent extends Component<any, any> {
2+
__v: VNode;
3+
__c: (error: Promise<void>, suspendingVNode: VNode) => void;
4+
}
5+
6+
export interface VNode<P = any> extends preact.VNode<P> {
7+
__c: AugmentedComponent;
8+
__e?: Element | Text;
9+
__u: number;
10+
__h: boolean;
11+
__v?: VNode<P>;
12+
__k: Array<VNode<any>> | null;
13+
}
14+
15+
export {}

src/router.d.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,12 @@ interface LocationHook {
1919
}
2020
export const useLocation: () => LocationHook;
2121

22-
export const useRoute: () => {
22+
interface RouteHook {
2323
path: string;
2424
query: Record<string, string>;
2525
params: Record<string, string>;
26-
};
26+
}
27+
export const useRoute: () => RouteHook;
2728

2829
interface RoutableProps {
2930
path?: string;

src/router.js

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
import { h, createContext, cloneElement, toChildArray } from 'preact';
22
import { useContext, useMemo, useReducer, useLayoutEffect, useRef } from 'preact/hooks';
33

4+
/**
5+
* @template T
6+
* @typedef {import('preact').RefObject<T>} RefObject
7+
* @typedef {import('./internal.d.ts').VNode} VNode
8+
*/
9+
410
let push;
511
const UPDATE = (state, url) => {
612
push = undefined;
@@ -96,6 +102,7 @@ export function LocationProvider(props) {
96102
}
97103

98104
const RESOLVED = Promise.resolve();
105+
/** @this {import('./internal.d.ts').AugmentedComponent} */
99106
export function Router(props) {
100107
const [c, update] = useReducer(c => c + 1, 0);
101108

@@ -107,27 +114,28 @@ export function Router(props) {
107114
// Monotonic counter used to check if an un-suspending route is still the current route:
108115
const count = useRef(0);
109116
// The current route:
110-
const cur = useRef();
117+
const cur = /** @type {RefObject<VNode<any>>} */ (useRef());
111118
// Previous route (if current route is suspended):
112-
const prev = useRef();
119+
const prev = /** @type {RefObject<VNode<any>>} */ (useRef());
113120
// A not-yet-hydrated DOM root to remove once we commit:
114-
const pendingBase = useRef();
121+
const pendingBase = /** @type {RefObject<Element | Text>} */ (useRef());
115122
// has this component ever successfully rendered without suspending:
116123
const hasEverCommitted = useRef(false);
117124
// was the most recent render successful (did not suspend):
118-
const didSuspend = useRef();
125+
const didSuspend = /** @type {RefObject<boolean>} */ (useRef());
119126
didSuspend.current = false;
120127
// has the route component changed
121128
const routeChanged = useRef(false);
122129

123-
let pr, d, m;
124-
toChildArray(props.children).some(vnode => {
125-
const matches = exec(rest, vnode.props.path, (m = { ...vnode.props, path: rest, query, params, rest: '' }));
126-
if (matches) return (pr = cloneElement(vnode, m));
127-
if (vnode.props.default) d = cloneElement(vnode, m);
130+
let pathRoute, defaultRoute, matchProps;
131+
toChildArray(props.children).some((/** @type {VNode<any>} */ vnode) => {
132+
const matches = exec(rest, vnode.props.path, (matchProps = { ...vnode.props, path: rest, query, params, rest: '' }));
133+
if (matches) return (pathRoute = cloneElement(vnode, matchProps));
134+
if (vnode.props.default) defaultRoute = cloneElement(vnode, matchProps);
128135
});
129136

130-
let incoming = pr || d;
137+
/** @type {VNode<any> | undefined} */
138+
let incoming = pathRoute || defaultRoute;
131139
useMemo(() => {
132140
prev.current = cur.current;
133141

@@ -143,7 +151,8 @@ export function Router(props) {
143151

144152
const isHydratingSuspense = cur.current && cur.current.__u & MODE_HYDRATE && cur.current.__u & MODE_SUSPENDED;
145153
const isHydratingBool = cur.current && cur.current.__h;
146-
cur.current = h(RouteContext.Provider, { value: m }, incoming);
154+
// @ts-ignore
155+
cur.current = /** @type {VNode<any>} */ (h(RouteContext.Provider, { value: matchProps }, incoming));
147156
if (isHydratingSuspense) {
148157
cur.current.__u |= MODE_HYDRATE;
149158
cur.current.__u |= MODE_SUSPENDED;
@@ -242,10 +251,12 @@ const RenderRef = ({ r }) => r.current;
242251

243252
Router.Provider = LocationProvider;
244253

245-
/** @typedef {{ url: string, path: string, query: object, route, wasPush: boolean }} RouteInfo */
246-
247-
LocationProvider.ctx = createContext(/** @type {RouteInfo} */ ({}));
248-
const RouteContext = createContext({});
254+
LocationProvider.ctx = createContext(
255+
/** @type {import('./router.d.ts').LocationHook & { wasPush: boolean }} */ ({})
256+
);
257+
const RouteContext = createContext(
258+
/** @type {import('./router.d.ts').RouteHook & { rest: string }} */ ({})
259+
);
249260

250261
export const Route = props => h(props.component, props);
251262

0 commit comments

Comments
 (0)