Skip to content

Commit

Permalink
feat: all static page types are inferred
Browse files Browse the repository at this point in the history
TODO
- Create a union type of all possible paths given the pages
- Update tests and refactor examples to match new api
  • Loading branch information
tylersayshi committed Sep 7, 2024
1 parent 692774d commit 92e5829
Show file tree
Hide file tree
Showing 2 changed files with 27 additions and 10 deletions.
33 changes: 26 additions & 7 deletions packages/waku/src/router/create-pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ type Split<Str extends string, Del extends string | number> = string extends Str
? [T, ...Split<U, Del>]
: [Str];

/**
* This helper makes types more readable
* @see https://www.totaltypescript.com/concepts/the-prettify-helper
*/
type Prettify<T> = { [K in keyof T]: T[K] } & {};

/** Assumes that the path is a part of a slug path. */
type IsValidPathItem<T> = T extends `/${infer _}`
? false
Expand Down Expand Up @@ -144,33 +150,46 @@ export type CreatePage = <
PagePath extends string,
SlugKey extends string,
WildSlugKey extends string,
Render extends 'static' | 'dynamic',
>(
page: (
| {
render: 'static';
render: Extract<Render, 'static'>;
path: PathWithoutSlug<PagePath>;
component: FunctionComponent<RouteProps>;
}
| {
render: 'static';
render: Extract<Render, 'static'>;
path: PathWithStaticSlugs<PagePath>;
staticPaths: StaticSlugRoutePaths<PagePath>;
component: FunctionComponent<RouteProps & Record<SlugKey, string>>;
}
| {
render: 'dynamic';
render: Extract<Render, 'dynamic'>;
path: PathWithoutSlug<PagePath>;
component: FunctionComponent<RouteProps>;
}
| {
render: 'dynamic';
render: Extract<Render, 'dynamic'>;
path: PathWithWildcard<PagePath, SlugKey, WildSlugKey>;
component: FunctionComponent<
RouteProps & Record<SlugKey, string> & Record<WildSlugKey, string[]>
>;
}
) & { unstable_disableSSR?: boolean },
) => PagePath;
) => Prettify<
Omit<
Exclude<typeof page, { path: never } | { render: never }>,
'unstable_disableSSR'
>
>;

/** Generic type that represents any page. This is used to infer the return type of createPages. */
type AnyPage = {
path: string;
render: 'static' | 'dynamic';
staticPaths?: string[];
};

export type CreateLayout = <T extends string>(layout: {
render: 'static' | 'dynamic';
Expand All @@ -180,7 +199,7 @@ export type CreateLayout = <T extends string>(layout: {
>;
}) => void;

export function createPages<AllPages extends string[]>(
export function createPages<AllPages extends AnyPage[]>(
fn: (fns: {
createPage: CreatePage;
createLayout: CreateLayout;
Expand Down Expand Up @@ -297,7 +316,7 @@ export function createPages<AllPages extends string[]>(
} else {
throw new Error('Invalid page configuration');
}
return page.path;
return page as Exclude<typeof page, { path: never } | { render: never }>;
};

const createLayout: CreateLayout = (layout) => {
Expand Down
4 changes: 1 addition & 3 deletions packages/waku/src/router/test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,4 @@ export const router = createPages(async ({ createPage }) => {
// Note: This abstracts away the return type from the final router
type Router = typeof router;

type InferredRouterPath = Awaited<
NonNullable<Router['DO_NOT_USE_ready']>
>[number];
type InferredRouter = Awaited<NonNullable<Router['DO_NOT_USE_ready']>>[number];

Check failure on line 36 in packages/waku/src/router/test.tsx

View workflow job for this annotation

GitHub Actions / test

'InferredRouter' is defined but never used. Allowed unused vars must match /^_/u

0 comments on commit 92e5829

Please sign in to comment.