Skip to content

Commit 7234191

Browse files
piscisaureusqti3e
authored andcommitted
Make router type-safe
1 parent ba5b9cd commit 7234191

File tree

2 files changed

+30
-11
lines changed

2 files changed

+30
-11
lines changed

src/app.tsx

+28-9
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";
@@ -27,15 +27,34 @@ import { Notebook } from "./components/notebook";
2727
import { Profile } from "./components/profile";
2828
import { Recent } from "./components/recent";
2929

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

34-
interface BindState {
35-
data: { [key: string]: string };
51+
interface BindStateError {
52+
data: null;
3653
error: string;
3754
}
3855

56+
type BindState<P> = BindStateNormal<P> | BindStateError;
57+
3958
/**
4059
* This react HOC can be used to bind result of some async
4160
* methods to props of the given component (C).
@@ -48,8 +67,8 @@ interface BindState {
4867
* }
4968
* });
5069
*/
51-
function bind(C, bindProps: BindProps) {
52-
return class extends Component<any, BindState> {
70+
function bind<P>(C: ComponentConstructor<P, {}>, bindProps: BindProps<P>) {
71+
return class extends Component<BoundProps<P>, BindState<P>> {
5372
state = { data: null, error: null };
5473
prevMatches = null;
5574
componentRef;
@@ -61,7 +80,7 @@ function bind(C, bindProps: BindProps) {
6180
async loadData() {
6281
if (equal(this.props.matches, this.prevMatches)) return;
6382
this.prevMatches = this.props.matches;
64-
const data = {};
83+
const data: Partial<P> = {};
6584
for (const key in bindProps) {
6685
if (!bindProps[key]) continue;
6786
try {
@@ -71,7 +90,7 @@ function bind(C, bindProps: BindProps) {
7190
return;
7291
}
7392
}
74-
this.setState({ data, error: null });
93+
this.setState({ data: data as P, error: null });
7594
}
7695

7796
render() {

src/nb_test.ts

+2-2
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)