Skip to content

Commit 7332616

Browse files
committed
Make router type-safe
1 parent 1e67a10 commit 7332616

File tree

2 files changed

+28
-11
lines changed

2 files changed

+28
-11
lines changed

src/app.tsx

+26-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,32 @@ 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;
3238
}
3339

34-
interface BindState {
35-
data: { [key: string]: string };
40+
type BindProps<P> = {
41+
[K in keyof P]?: (props: ReadOnly<Partial<P> & PageProps>) => Promise<P[K]>
42+
};
43+
44+
interface BindStateNormal<S> {
45+
data: { [K in keyof S]: S[K] };
46+
error: null;
47+
}
48+
49+
interface BindStateError {
50+
data: null;
3651
error: string;
3752
}
3853

54+
type BindState<S> = BindStateNormal<S> | BindStateError;
55+
3956
/**
4057
* This react HOC can be used to bind result of some async
4158
* methods to props of the given component (C).
@@ -48,8 +65,8 @@ interface BindState {
4865
* }
4966
* });
5067
*/
51-
function bind(C, bindProps: BindProps) {
52-
return class extends Component<any, BindState> {
68+
function bind<P>(C: ComponentConstructor<P, {}>, bindProps: BindProps<P>) {
69+
return class extends Component<Partial<P> & PageProps, BindState<P>> {
5370
state = { data: null, error: null };
5471
prevMatches = null;
5572
componentRef;
@@ -61,7 +78,7 @@ function bind(C, bindProps: BindProps) {
6178
async loadData() {
6279
if (equal(this.props.matches, this.prevMatches)) return;
6380
this.prevMatches = this.props.matches;
64-
const data = {};
81+
const data: Partial<P> = {};
6582
for (const key in bindProps) {
6683
if (!bindProps[key]) continue;
6784
try {
@@ -71,7 +88,7 @@ function bind(C, bindProps: BindProps) {
7188
return;
7289
}
7390
}
74-
this.setState({ data, error: null });
91+
this.setState({ data: data as P, error: null });
7592
}
7693

7794
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)