Skip to content

Commit a4ebd6f

Browse files
committed
fix(router): accept a redirect function in RedirectRouteMeta
`RedirectRouteMeta.redirectTo` was typed `string`, so a `RouteMeta` could not hold the `RedirectFunction` that Angular's `Route` accepts and that `toRouteConfig` passes through unchanged. It now takes Angular's `Route['redirectTo']` without `undefined`, and the typed route helpers exclude redirect metas by the same shape. The runtime checks that decide whether a page is a redirect test for a nullish `redirectTo` instead of a falsy one, so `toRouteConfig`, the route builder's dev warning and the route diagnostics share one rule.
1 parent 060bd60 commit a4ebd6f

5 files changed

Lines changed: 37 additions & 6 deletions

File tree

‎packages/router/src/lib/models.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ export interface DefaultRouteMeta<
7676
}
7777

7878
export interface RedirectRouteMeta {
79-
redirectTo: string;
79+
redirectTo: NonNullable<Route['redirectTo']>;
8080
pathMatch?: Route['pathMatch'];
8181
}
8282

‎packages/router/src/lib/route-builder.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ function toRoutes<TFile>(
243243
module!().then((m) => {
244244
if (import.meta.env.DEV) {
245245
const hasModuleDefault = !!m.default;
246-
const hasRedirect = !!m.routeMeta?.redirectTo;
246+
const hasRedirect = m.routeMeta?.redirectTo != null;
247247

248248
if (!hasModuleDefault && !hasRedirect) {
249249
console.warn(

‎packages/router/src/lib/route-config.spec.ts‎

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,14 @@
11
import { provideHttpClient, withInterceptors } from '@angular/common/http';
22
import { PLATFORM_ID, TransferState } from '@angular/core';
33
import { TestBed } from '@angular/core/testing';
4-
import type { ActivatedRouteSnapshot } from '@angular/router';
4+
import type {
5+
ActivatedRouteSnapshot,
6+
PartialMatchRouteSnapshot,
7+
} from '@angular/router';
58
import { afterEach, describe, expect, it, vi } from 'vitest';
69

710
import { API_PREFIX, BASE_URL, INTERNAL_FETCH } from '../../tokens/src';
11+
import type { RouteMeta } from './models';
812
import { toRouteConfig } from './route-config';
913
import { ANALOG_META_KEY, ANALOG_PAGE_ENDPOINTS } from './endpoints';
1014
import { requestContextInterceptor } from './request-context';
@@ -23,6 +27,23 @@ describe('toRouteConfig', () => {
2327
expect(config.redirectTo).toBe('/home');
2428
});
2529

30+
it('returns a redirect function config unchanged', () => {
31+
const redirectTo = ({ params }: PartialMatchRouteSnapshot) =>
32+
`/users/${params['id']}`;
33+
const meta: RouteMeta = { redirectTo, pathMatch: 'full' };
34+
const config = toRouteConfig(meta);
35+
36+
expect(config.redirectTo).toBe(redirectTo);
37+
expect(config.pathMatch).toBe('full');
38+
});
39+
40+
it('keeps redirectTo off non-redirect metas', () => {
41+
// @ts-expect-error redirectTo belongs to redirect routes only
42+
const meta: RouteMeta = { title: 'Users', redirectTo: '/users' };
43+
44+
expect(toRouteConfig(meta).redirectTo).toBe('/users');
45+
});
46+
2647
// Regression: content routes (from .md files in the pages directory) are
2748
// built by route-builder.ts WITHOUT setting ANALOG_META_KEY on the route
2849
// config — only page routes (.page.ts) get the symbol. The `load`

‎packages/router/src/lib/route-config.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,5 +75,5 @@ export function toRouteConfig(
7575
function isRedirectRouteMeta(
7676
routeMeta: RouteMeta<never>,
7777
): routeMeta is RedirectRouteMeta {
78-
return !!routeMeta.redirectTo;
78+
return routeMeta.redirectTo != null;
7979
}

‎packages/router/src/lib/to-route.ts‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,12 @@ type InheritedRouteData<Metas, Data = EmptyObject> = Metas extends [
184184
]
185185
? InheritedRouteData<
186186
Rest,
187-
Merge<Data, RouteMetaData<Exclude<Meta, { redirectTo: string }>>>
187+
Merge<
188+
Data,
189+
RouteMetaData<
190+
Exclude<Meta, { redirectTo: NonNullable<Route['redirectTo']> }>
191+
>
192+
>
188193
>
189194
: Data;
190195

@@ -203,7 +208,12 @@ type InheritedRouteResources<Metas, Resources = EmptyObject> = Metas extends [
203208
]
204209
? InheritedRouteResources<
205210
Rest,
206-
Merge<Resources, RouteResourceMap<Exclude<Meta, { redirectTo: string }>>>
211+
Merge<
212+
Resources,
213+
RouteResourceMap<
214+
Exclude<Meta, { redirectTo: NonNullable<Route['redirectTo']> }>
215+
>
216+
>
207217
>
208218
: Resources;
209219

0 commit comments

Comments
 (0)