From 213501c8fd34350e0b059a746c449bcfb6db0d73 Mon Sep 17 00:00:00 2001 From: Dario Gieselaar Date: Sun, 23 Jan 2022 10:25:44 +0100 Subject: [PATCH] Further simplify types --- .../src/create_router.test.tsx | 51 +++++------ .../src/create_router.ts | 2 +- .../src/types/index.ts | 90 +++++++++---------- .../app/backend_inventory/index.tsx | 1 - 4 files changed, 63 insertions(+), 81 deletions(-) diff --git a/packages/kbn-typed-react-router-config/src/create_router.test.tsx b/packages/kbn-typed-react-router-config/src/create_router.test.tsx index 9837d45ddd8690d..d29079f37ec1239 100644 --- a/packages/kbn-typed-react-router-config/src/create_router.test.tsx +++ b/packages/kbn-typed-react-router-config/src/create_router.test.tsx @@ -10,16 +10,13 @@ import * as t from 'io-ts'; import { toNumberRt } from '@kbn/io-ts-utils'; import { createRouter } from './create_router'; import { createMemoryHistory } from 'history'; -import { route } from './route'; describe('createRouter', () => { - const routes = route([ - { - path: '/', + const routes = { + '/': { element: <>, - children: [ - { - path: '/', + children: { + '/': { element: <>, params: t.type({ query: t.type({ @@ -32,31 +29,27 @@ describe('createRouter', () => { rangeFrom: 'now-30m', }, }, - children: [ - { - path: '/services/{serviceName}/errors', + children: { + '/services/{serviceName}/errors': { element: <>, params: t.type({ path: t.type({ serviceName: t.string, }), }), - children: [ - { - path: '/services/{serviceName}/errors/{groupId}', + children: { + '/services/{serviceName}/errors/{groupId}': { element: <>, params: t.type({ path: t.type({ groupId: t.string }), }), }, - { - path: '/services/{serviceName}/errors', + '/services/{serviceName}/errors': { element: <>, }, - ], + }, }, - { - path: '/services', + '/services': { element: <>, params: t.type({ query: t.type({ @@ -64,13 +57,11 @@ describe('createRouter', () => { }), }), }, - { - path: '/services/{serviceName}', + '/services/{serviceName}': { element: <>, - children: [ - { + children: { + '/services/{serviceName}': { element: <>, - path: '/services/{serviceName}', params: t.type({ path: t.type({ serviceName: t.string, @@ -81,10 +72,9 @@ describe('createRouter', () => { }), }), }, - ], + }, }, - { - path: '/traces', + '/traces': { element: <>, params: t.type({ query: t.type({ @@ -93,8 +83,7 @@ describe('createRouter', () => { }), }), }, - { - path: '/service-map', + '/service-map': { element: <>, params: t.type({ query: t.type({ @@ -102,11 +91,11 @@ describe('createRouter', () => { }), }), }, - ], + }, }, - ], + }, }, - ] as const); + }; let history = createMemoryHistory(); const router = createRouter(routes); diff --git a/packages/kbn-typed-react-router-config/src/create_router.ts b/packages/kbn-typed-react-router-config/src/create_router.ts index f3f83dfecdc47c2..494540005224a42 100644 --- a/packages/kbn-typed-react-router-config/src/create_router.ts +++ b/packages/kbn-typed-react-router-config/src/create_router.ts @@ -37,7 +37,7 @@ export function createRouter(routes: TRoutes): Router< Object.entries((route.children as RouteMap | undefined) ?? {})?.map(([path, child]) => toReactRouterConfigRoute({ ...child, path }) ) ?? [], - exact: !route.children?.length, + exact: !route.children || Object.values(route.children).length === 0, path: toReactRouterPath(route.path), }; diff --git a/packages/kbn-typed-react-router-config/src/types/index.ts b/packages/kbn-typed-react-router-config/src/types/index.ts index f768990ac014a10..647860631725bd9 100644 --- a/packages/kbn-typed-react-router-config/src/types/index.ts +++ b/packages/kbn-typed-react-router-config/src/types/index.ts @@ -12,7 +12,14 @@ import { ReactElement } from 'react'; import { RequiredKeys, ValuesType, UnionToIntersection } from 'utility-types'; import { NormalizePath } from './utils'; -export type PathsOf = keyof MapRoutes & string; +export type PathsOf = string & + ValuesType<{ + [key in keyof TRouteMap]: + | key + | (TRouteMap[key] extends { children: RouteMap } + ? AppendPath | PathsOf + : never); + }>; export type RouteMap = Record; @@ -42,71 +49,55 @@ export interface RouteMatch { }; } -type ToRouteMatch = TRoutes extends [] - ? [] - : TRoutes extends [Route] +type ToRouteMatch = TRoutes extends [Route] ? [RouteMatch] - : TRoutes extends [Route, ...infer TTail] - ? TTail extends Route[] - ? [RouteMatch, ...ToRouteMatch] - : [] - : []; - -type UnwrapRouteMap = TRoute extends { - parents: Route[]; -} - ? ToRouteMatch<[...TRoute['parents'], Omit]> - : ToRouteMatch<[Omit]>; + : TRoutes extends [Route, ...infer TNextRoutes] + ? [RouteMatch, ...(TNextRoutes extends Route[] ? ToRouteMatch : [])] + : TRoutes extends [] + ? [] + : never; -export type Match = MapRoutes extends { - [key in TPath]: Route; -} - ? UnwrapRouteMap[TPath]> - : []; +export type Match = MapRoutes[TPath]; export interface DefaultOutput { path: {}; query: {}; } -type OutputOfRouteMatch = TRouteMatch extends { - route: { params: t.Type }; +type OutputOfRoute = TRoute extends { + params: t.Type; } - ? t.OutputOf - : DefaultOutput; + ? t.OutputOf + : {}; -type OutputOfMatches = TRouteMatches extends [RouteMatch] - ? OutputOfRouteMatch - : TRouteMatches extends [RouteMatch, ...infer TNextRouteMatches] - ? OutputOfRouteMatch & - (TNextRouteMatches extends RouteMatch[] ? OutputOfMatches : DefaultOutput) - : TRouteMatches extends RouteMatch[] - ? OutputOfRouteMatch> - : DefaultOutput; +type OutputOfRoutes = TRoutes extends [Route] + ? OutputOfRoute + : TRoutes extends [Route, ...infer TNextRoutes] + ? OutputOfRoute & (TNextRoutes extends Route[] ? OutputOfRoutes : {}) + : {}; -export type OutputOf> = OutputOfMatches< +export type OutputOf> = OutputOfRoutes< Match > & DefaultOutput; -type TypeOfRouteMatch = TRouteMatch extends { - route: { params: t.Type }; +type TypeOfRoute = TRoute extends { + params: t.Type; } - ? t.TypeOf + ? t.TypeOf : {}; -type TypeOfMatches = TRouteMatches extends [RouteMatch] - ? TypeOfRouteMatch - : TRouteMatches extends [RouteMatch, ...infer TNextRouteMatches] - ? TypeOfRouteMatch & - (TNextRouteMatches extends RouteMatch[] ? TypeOfMatches : {}) +type TypeOfRoutes = TRoutes extends [Route] + ? TypeOfRoute + : TRoutes extends [Route, ...infer TNextRoutes] + ? TypeOfRoute & (TNextRoutes extends Route[] ? TypeOfRoutes : {}) : {}; export type TypeOf< TRoutes extends RouteMap, TPath extends PathsOf, TWithDefaultOutput extends boolean = true -> = TypeOfMatches> & (TWithDefaultOutput extends true ? DefaultOutput : {}); +> = TypeOfRoutes> & (TWithDefaultOutput extends true ? DefaultOutput : {}); export type TypeAsArgs = keyof TObject extends never ? [] @@ -122,8 +113,8 @@ export interface Router { matchRoutes>( path: TPath, location: Location - ): Match; - matchRoutes(location: Location): Match>; + ): ToRouteMatch>; + matchRoutes(location: Location): ToRouteMatch>>; getParams>( path: TPath, location: Location @@ -168,7 +159,7 @@ type MaybeUnion, U extends Record> = type MapRoute = MaybeUnion< { - [key in TRoute['path']]: TRoute & { parents: TParents }; + [key in TRoute['path']]: [...TParents, TRoute]; }, TRoute extends { children: RouteMap } ? MaybeUnion< @@ -194,7 +185,7 @@ type FromRouteMap< type MapRoutes = FromRouteMap< TRouteMap, TParents -> extends Record +> extends Record ? FromRouteMap : never; @@ -384,7 +375,7 @@ type MapRoutes; // type Paths = PathsOf; -// type Bar = ValuesType>['route']['path']; +// type Bar = Match; // type Foo = OutputOf; // type Baz = OutputOf; @@ -394,4 +385,7 @@ type MapRoutes