Skip to content

Commit 7da0319

Browse files
piscisaureusqti3e
authored andcommitted
Make router type-safe
1 parent 884fba3 commit 7da0319

File tree

2 files changed

+31
-12
lines changed

2 files changed

+31
-12
lines changed

src/app.tsx

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
limitations under the License.
1414
*/
1515

16-
import { Component, h } from "preact";
16+
import { Component, ComponentConstructor, h } from "preact";
1717
import * as db from "./db";
1818
import { push, Router } from "./router";
1919
import * as types from "./types";
@@ -28,15 +28,34 @@ import { Notebook } from "./components/notebook";
2828
import { Profile } from "./components/profile";
2929
import { Recent } from "./components/recent";
3030

31-
interface BindProps {
32-
[key: string]: (props: any) => Promise<any>;
31+
type Partial<T> = { [K in keyof T]?: T[K] };
32+
33+
type ReadOnly<T> = { readonly [K in keyof T]: T[K] };
34+
35+
interface PageProps {
36+
path: string;
37+
matches?: { [key: string]: string };
38+
onReady?: () => void;
39+
}
40+
41+
type BindProps<P> = {
42+
[K in keyof P]?: (props: ReadOnly<BoundProps<P>>) => Promise<P[K]>
43+
};
44+
45+
type BoundProps<P> = PageProps & BindProps<P>;
46+
47+
interface BindStateNormal<P> {
48+
data: { [K in keyof P]: P[K] };
49+
error: null;
3350
}
3451

35-
interface BindState {
36-
data: { [key: string]: string };
52+
interface BindStateError {
53+
data: null;
3754
error: string;
3855
}
3956

57+
type BindState<P> = BindStateNormal<P> | BindStateError;
58+
4059
/**
4160
* This react HOC can be used to bind result of some async
4261
* methods to props of the given component (C).
@@ -49,8 +68,8 @@ interface BindState {
4968
* }
5069
* });
5170
*/
52-
function bind(C, bindProps: BindProps) {
53-
return class extends Component<any, BindState> {
71+
function bind<P>(C: ComponentConstructor<P, {}>, bindProps: BindProps<P>) {
72+
return class extends Component<BoundProps<P>, BindState<P>> {
5473
state = { data: null, error: null };
5574
prevMatches = null;
5675
componentRef;
@@ -62,7 +81,7 @@ function bind(C, bindProps: BindProps) {
6281
async loadData() {
6382
if (equal(this.props.matches, this.prevMatches)) return;
6483
this.prevMatches = this.props.matches;
65-
const data = {};
84+
const data: Partial<P> = {};
6685
for (const key in bindProps) {
6786
if (!bindProps[key]) continue;
6887
try {
@@ -72,7 +91,7 @@ function bind(C, bindProps: BindProps) {
7291
return;
7392
}
7493
}
75-
this.setState({ data, error: null });
94+
this.setState({ data: data as P, error: null });
7695
}
7796

7897
render() {
@@ -170,7 +189,7 @@ export const NotebookPage = bind(Notebook, {
170189
}
171190
});
172191

173-
export const HomePage = bind(Home, {});
192+
export const HomePage = bind(Home as any, {});
174193
// tslint:enable:variable-name
175194

176195
export interface AppState {

src/nb_test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ function resetPage() {
185185
function renderProfile(profileUid: string) {
186186
const promise = createResolvable();
187187
resetPage();
188-
const el = h(ProfilePage, {
188+
const el = h(ProfilePage as any, {
189189
matches: {
190190
userId: profileUid
191191
},
@@ -199,7 +199,7 @@ async function renderAnonNotebook(): Promise<Notebook> {
199199
const promise = createResolvable();
200200
resetPage();
201201
let notebookRoot;
202-
const el = h(NotebookPage, {
202+
const el = h(NotebookPage as any, {
203203
matches: {
204204
nbId: "default"
205205
},

0 commit comments

Comments
 (0)