|
|
|
@ -1,4 +1,4 @@ |
|
|
|
|
import { ApiResponse, Sitemap } from './types'; |
|
|
|
|
import { ApiResponse, Sitemap, Simplify } from './types'; |
|
|
|
|
|
|
|
|
|
type Subtree = { |
|
|
|
|
name: string; |
|
|
|
@ -6,10 +6,35 @@ type Subtree = { |
|
|
|
|
children: Sitemap[]; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
type GetBaseParentIdType<TParentId extends number | null> = TParentId extends null ? null : number; |
|
|
|
|
|
|
|
|
|
type ExtractEntryByParentId<TEntry extends ApiResponse[number], TParentId extends number | null> =
|
|
|
|
|
//Extract<TEntry, { readonly parent: TParentId }>;
|
|
|
|
|
Simplify<{ readonly parent: GetBaseParentIdType<TParentId> } extends Pick<TEntry, 'parent'> ? TEntry : Extract<TEntry, { readonly parent: TParentId }>>; |
|
|
|
|
|
|
|
|
|
type ExtractEntriesByParentId<TApiResponse extends ApiResponse, TParentId extends number | null> = ExtractEntryByParentId<TApiResponse[number], TParentId>; |
|
|
|
|
|
|
|
|
|
type TypedSitemapEntry<TApiResponse extends ApiResponse, TEntry extends TApiResponse[number]> = TEntry extends unknown ? { |
|
|
|
|
name: TEntry['slug'], |
|
|
|
|
id: TEntry['id'], |
|
|
|
|
children: TypedSitemapEntries<TApiResponse, TEntry['id']> |
|
|
|
|
} : never; |
|
|
|
|
|
|
|
|
|
type TypedSitemapEntries<TApiResponse extends ApiResponse, TParentId extends number | null> = TypedSitemapEntry<TApiResponse, ExtractEntriesByParentId<TApiResponse, TParentId>>[]; |
|
|
|
|
|
|
|
|
|
//type NeverToNull<TSitemap> = TSitemap extends never ? null : TSitemap;
|
|
|
|
|
|
|
|
|
|
//export type TypedSitemap<TApiResponse extends ApiResponse> = Simplify<NeverToNull<Simplify<TypedSitemapEntries<TApiResponse, null>[number]>>>;
|
|
|
|
|
export type TypedSitemap<TApiResponse extends ApiResponse> = Simplify<TypedSitemapEntries<TApiResponse, null>[number]>; |
|
|
|
|
|
|
|
|
|
//const z = [{slug: 'a', id: 1, parent: 1 }];
|
|
|
|
|
//type Q = NeverToNull<TypedSitemap<typeof z>>;
|
|
|
|
|
//type A = never extends never ? 'a' : 'b';
|
|
|
|
|
|
|
|
|
|
// alternatively, for full TS experience, if I had more time I'd also implement parsing in TS so that this declaration would look like:
|
|
|
|
|
// export const createSitemap = <TResponse extends ApiResponse>(apiResponse: TResponse): Sitemap<TResponse> => {
|
|
|
|
|
// and calling e.g. `createSitemap(const sample data json)` would return value with type `const sample sitemap`, rather than just general sitemap
|
|
|
|
|
export const createSitemap = (apiResponse: ApiResponse): Sitemap | null => { |
|
|
|
|
export const createSitemap = <TResponse extends ApiResponse>(apiResponse: ApiResponse): TypedSitemap<TResponse> => { |
|
|
|
|
const subtrees = new Map<number, Subtree>( |
|
|
|
|
apiResponse.map(({ id, slug }) => [ |
|
|
|
|
id, |
|
|
|
@ -36,5 +61,5 @@ export const createSitemap = (apiResponse: ApiResponse): Sitemap | null => { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return root; |
|
|
|
|
return root as any; |
|
|
|
|
}; |
|
|
|
|