I have been working on implementing a type-safe router in TypeScript and I am facing challenges with inferring types.
export interface Route<Args> {
match(path: string): Args | void;
build(args: Args): string;
}
export type Routes<State> = {[Tag in keyof State]: Route<State[Tag]>};
export interface Router<State> {
match(path: string): Partial<State> | void;
build(state: Partial<State>): string;
}
export function createRouter<State>(routes: Routes<State>): Router<State> {
/* ... */ return {} as any;
}
const root: Route<{}> = {
match: (path) => /* ... */ undefined,
build: () => '/'
};
const blog: Route<{ id: string }> = {
match: (path) => /* ... */ undefined,
build: ({ id }) => '/blog/' + id
};
const router1 = createRouter({ root, blog });
const router2 = createRouter<{ root: {}, blog: { id: string } }>({ root, blog });
const router3 = createRouter(<Routes<{ root: {}, blog: { id: string } }>>{ root, blog });
The inferred type of router1
is a
Router<{root: any, blog: any}>
.
However, my expectation was for the router to have a type of Router<{root:{}, blog:{id:string}}>
.
I attempted to add a type parameter (as seen in router2
) and it worked as anticipated.
I also noticed that TypeScript cannot infer the type of the routes
object, so I explicitly added the type (shown in router3
), which also resolved the issue.
Is there a way to address this problem without explicitly adding types? I would like to understand why TypeScript interprets value types as any in this scenario.