Package Exports
- type-route
This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (type-route) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.
Readme
Disclaimer: type-route has not yet reached version 1.0. The api is unstable and subject to change without warning. The library itself may never reach version 1.0. Early feedback is welcome, but using this library in its current state for anything other than a throw away project is not recommended.
Introduction
The APIs of existing routing libraries aren't optimized for static analysis. Users of these libraries suffer from a sub-par developer experience because of this. type-route
was designed with a fully statically analyzable API in mind. This means great developer tooling out of the box when using TypeScript or an editor like VSCode whose JavaScript experience is powered by TypeScript under the hood. The API makes extensive use of type inference and almost no explicit type annotations are needed to achieve a fully typed code base. type-route
is built on top of the same core history library as React Router. type-route
simply provides a more modern and flexible high-level API for interacting with the same foundational tool.
Getting Started
Install
npm install type-route
Code
import { createRouter, defineRoute } from "type-route";
const { routes, listen } = createRouter({
home: defineRoute("/"),
postList: defineRoute(
{
page: "query.param.number.optional"
},
p => `/post`
),
post: defineRoute(
{
postId: "path.param.string"
},
p => `/post/${p.postId}`
)
});
listen(nextRoute => {
console.log(nextRoute);
});
routes.home.push();
// url "/"
// logs { name: "home", params: {} }
routes.postList.push();
// url "/post"
// logs { name: "postList", params: {} }
routes.postList.push({ page: 1 });
// url "/post?page=1"
// logs { name: "postList", params: { page: 1 } }
routes.post.push({ postId: "abc" });
// url "/post/abc"
// logs { name: "postId", params: { postId: "abc" } }
Usage Example with React
type-route
isn't coupled to any specific UI framework. Originally, it was intended to be a React specific routing solution. Designing the API, however, revealed that a UI framework agnostic design actually worked better with the project goals of top-notch developer tooling and great React integration than a design specifically coupled to React. The result is a very flexible library that happens to work seamlessly with React.
import { createRoute, defineRoute, Router } from "type-route";
const { routes, listen, getCurrentRoute } = createRouter({
home: defineRoute("/"),
postList: defineRoute(
{
page: "query.param.number.optional"
},
p => `/post`
),
post: defineRoute(
{
postId: "path.param.string"
},
p => `/post/${p.postId}`
)
});
function App() {
const [route, setRoute] = useState(getCurrentRoute());
useEffect(() => {
const listener = listen(nextRoute => {
setRoute(nextRoute);
});
return () => listener.remove();
}, []);
return <div>
<a {...routes.home.link()}>
Home
</a>
<a { ...routes.postList.link()}>
PostList
</a>
<a { ...routes.postList.link({ page: 1 })}>
PostList Page 1
</a>
<a { ...routes.post.link({ postId: "abc" })}>
Post abc
</a>
<Page route={route}/>
<div>
}
function Page(props: { route: Route<typeof routes}> }) {
const { route } = props;
switch(route.name) {
case routes.home.name:
return <HomePage/>;
case routes.postList.name:
return <PostListPage page={route.params.page}/>;
case routes.post.name:
return <PostPage postId={route.params.postId}/>;
default:
return <NotFoundPage/>;
}
}
function HomePage() {
return <div>Home</div>;
}
function PostListPage(props: { page?: number }) {
return <div>PostList {props.page}</div>;
}
function PostPage(props: { postId: string }) {
return <div>Post {props.postId}</div>;
}
function NotFoundPage() {
return <div>NotFound</div>;
}