Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: history typescript optimize #12632

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions packages/preset-umi/src/features/tmpFiles/tmpFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -426,13 +426,31 @@ if (process.env.NODE_ENV === 'development') {
headerImports.push(`import React from 'react';`);
}

const getAllPathRoutes = (routers: any) => {
const list: string[] = [];
const getPPath = (pId: string): string => {
const router = routers[pId];
if (routers[pId].parentId) {
return `${getPPath(router.parentId)}/${router.path}`;
}
return router.path;
};
for (const id of Object.keys(routers)) {
const data = routers[id];
const path = data.parentId ? `${getPPath(data.parentId)}/${data.path}` : data.path;
list.push(path);
}
return list;
};

api.writeTmpFile({
noPluginDir: true,
path: 'core/route.tsx',
tplPath: join(TEMPLATES_DIR, 'route.tpl'),
context: {
headerImports: headerImports.join('\n'),
routes: routesString,
allPathRouters: getAllPathRoutes(routesString),
fz6m marked this conversation as resolved.
Show resolved Hide resolved
routeComponents: await routesApi.getRouteComponents({
routes,
prefix,
Expand Down
109 changes: 2 additions & 107 deletions packages/preset-umi/templates/historyIntelli.tpl
Original file line number Diff line number Diff line change
@@ -1,69 +1,14 @@
import { getRoutes } from './route'
import type { History } from '{{{ historyPath }}}'

type Routes = Awaited<ReturnType<typeof getRoutes>>['routes']
type AllRoute = Routes[keyof Routes]
type IsRoot<T extends any> = 'parentId' extends keyof T ? false : true

// show `/` in not `layout / wrapper` only
type GetAllRouteWithoutLayout<Item extends AllRoute> = Item extends any
? 'isWrapper' extends keyof Item
? never
: 'isLayout' extends keyof Item
? never
: Item
: never
type AllRouteWithoutLayout = GetAllRouteWithoutLayout<AllRoute>
type IndexRoutePathname = '/' extends AllRouteWithoutLayout['path']
? '/'
: never

type GetChildrens<T extends any> = T extends any
? IsRoot<T> extends true
? never
: T
: never
type Childrens = GetChildrens<AllRoute>
type Root = Exclude<AllRoute, Childrens>
type AllIds = AllRoute['id']

type GetChildrensByParentId<
Id extends AllIds,
Item = AllRoute
> = Item extends any
? 'parentId' extends keyof Item
? Item['parentId'] extends Id
? Item
: never
: never
: never

type RouteObject<
Id extends AllIds,
Item = GetChildrensByParentId<Id>
> = IsNever<Item> extends true
? ''
: Item extends AllRoute
? {
[Key in Item['path'] as TrimSlash<Key>]: UnionMerge<
RouteObject<Item['id']>
>
}
: never

type GetRootRouteObject<Item extends Root> = Item extends Root
? {
[K in Item['path'] as TrimSlash<K>]: UnionMerge<RouteObject<Item['id']>>
}
: never
type MergedResult = UnionMerge<GetRootRouteObject<Root>>
type Routes = Awaited<ReturnType<typeof getRoutes>>['allPathRoutes'][number]

// --- patch history types ---

type HistoryTo = Parameters<History['push']>['0']
type HistoryPath = Exclude<HistoryTo, string>

type UmiPathname = Path<MergedResult> | (string & {})
type UmiPathname = Routes | (string & {})
interface UmiPath extends HistoryPath {
pathname: UmiPathname
}
Expand All @@ -83,53 +28,3 @@ export interface UmiHistory extends History {
goBack: UmiGoBack
{{/reactRouter5Compat}}
}

// --- type utils ---
type TrimLeftSlash<T extends string> = T extends `/${infer R}`
? TrimLeftSlash<R>
: T
type TrimRightSlash<T extends string> = T extends `${infer R}/`
? TrimRightSlash<R>
: T
type TrimSlash<T extends string> = TrimLeftSlash<TrimRightSlash<T>>

type IsNever<T> = [T] extends [never] ? true : false
type IsEqual<A, B> = (<G>() => G extends A ? 1 : 2) extends <G>() => G extends B
? 1
: 2
? true
: false

type UnionToIntersection<U> = (U extends any ? (k: U) => void : never) extends (
k: infer I
) => void
? I
: never
type UnionMerge<U> = UnionToIntersection<U> extends infer O
? { [K in keyof O]: O[K] }
: never

type ExcludeEmptyKey<T> = IsEqual<T, ''> extends true ? never : T

type PathConcat<
TKey extends string,
TValue,
N = TrimSlash<TKey>
> = TValue extends string
? ExcludeEmptyKey<N>
:
| ExcludeEmptyKey<N>
| `${N & string}${IsNever<ExcludeEmptyKey<N>> extends true
? ''
: '/'}${UnionPath<TValue>}`

type UnionPath<T> = {
[K in keyof T]-?: PathConcat<K & string, T[K]>
}[keyof T]

type MakeSureLeftSlash<T> = T extends any
? `/${TrimRightSlash<T & string>}`
: never

// exclude `/*`, because it always at the top of the IDE tip list
type Path<T, K = UnionPath<T>> = Exclude<MakeSureLeftSlash<K>, '/*'> | IndexRoutePathname
2 changes: 2 additions & 0 deletions packages/preset-umi/templates/route.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

export async function getRoutes() {
const routes = {{{ routes }}} as const;
const allPathRoutes = {{{ allPathRoutes }}} as const;
return {
routes,
allPathRoutes,
routeComponents: {{{ routeComponents }}},
};
}