Skip to content
Closed
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
Next Next commit
fix(router): make currentSnapshot required in CanMatchFn
it was only optional to avoid a breaking change in a minor

BREAKING CHANGE: The `currentSnapshot` parameter in `CanMatchFn` and the `canMatch` method of the `CanMatch` interface is now required. While this was already the behavior of the Router at runtime, existing class implementations of `CanMatch` must now include the third argument to satisfy the interface.
  • Loading branch information
atscott committed Mar 31, 2026
commit e9046e998a012fc0aa648966cfaefaf57df2a3e2
7 changes: 6 additions & 1 deletion adev/src/content/guide/routing/route-guards.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,11 +125,16 @@ It has access to the following default arguments:

- `route`: `Route` - The route configuration being evaluated
- `segments`: `UrlSegment[]` - The URL segments that have not been consumed by previous parent route evaluations
- `currentSnapshot: PartialMatchRouteSnapshot` - The current route snapshot up to this point in the matching process

It can return the [standard return guard types](#route-guard-return-types), but when it returns `false`, Angular tries other matching routes instead of completely blocking navigation.

```ts
export const featureToggleGuard: CanMatchFn = (route: Route, segments: UrlSegment[]) => {
export const featureToggleGuard: CanMatchFn = (
route: Route,
segments: UrlSegment[],
currentSnapshot: PartialMatchRouteSnapshot,
) => {
const featureService = inject(FeatureService);
return featureService.isFeatureEnabled('newDashboard');
};
Expand Down
4 changes: 2 additions & 2 deletions goldens/public-api/router/index.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -149,11 +149,11 @@ export type CanLoadFn = (route: Route, segments: UrlSegment[]) => MaybeAsync<Gua
// @public
export interface CanMatch {
// (undocumented)
canMatch(route: Route, segments: UrlSegment[], currentSnapshot?: PartialMatchRouteSnapshot): MaybeAsync<GuardResult>;
canMatch(route: Route, segments: UrlSegment[], currentSnapshot: PartialMatchRouteSnapshot): MaybeAsync<GuardResult>;
}

// @public
export type CanMatchFn = (route: Route, segments: UrlSegment[], currentSnapshot?: PartialMatchRouteSnapshot) => MaybeAsync<GuardResult>;
export type CanMatchFn = (route: Route, segments: UrlSegment[], currentSnapshot: PartialMatchRouteSnapshot) => MaybeAsync<GuardResult>;

// @public
export class ChildActivationEnd {
Expand Down
7 changes: 6 additions & 1 deletion packages/examples/router/route_functional_guards.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
CanActivateChildFn,
CanActivateFn,
CanMatchFn,
PartialMatchRouteSnapshot,
provideRouter,
ResolveFn,
Route,
Expand Down Expand Up @@ -111,7 +112,11 @@ bootstrapApplication(App, {
// #enddocregion

// #docregion CanMatchFn
const canMatchTeam: CanMatchFn = (route: Route, segments: UrlSegment[]) => {
const canMatchTeam: CanMatchFn = (
route: Route,
segments: UrlSegment[],
currentSnapshot: PartialMatchRouteSnapshot,
) => {
return inject(PermissionsService).canMatch(inject(UserToken));
};

Expand Down
14 changes: 8 additions & 6 deletions packages/router/src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1113,7 +1113,11 @@ export type CanDeactivateFn<T> = (
* class CanMatchTeamSection implements CanMatch {
* constructor(private permissions: Permissions, private currentUser: UserToken) {}
*
* canMatch(route: Route, segments: UrlSegment[]): Observable<boolean>|Promise<boolean>|boolean {
* canMatch(
* route: Route,
* segments: UrlSegment[],
* currentSnapshot: PartialMatchRouteSnapshot,
* ): Observable<boolean> | Promise<boolean> | boolean {
* return this.permissions.canAccess(this.currentUser, route, segments);
* }
* }
Expand Down Expand Up @@ -1154,7 +1158,7 @@ export interface CanMatch {
canMatch(
route: Route,
segments: UrlSegment[],
currentSnapshot?: PartialMatchRouteSnapshot,
currentSnapshot: PartialMatchRouteSnapshot,
): MaybeAsync<GuardResult>;
}

Expand All @@ -1172,9 +1176,7 @@ export interface CanMatch {
*
* @param route The route configuration.
* @param segments The URL segments that have not been consumed by previous parent route evaluations.
* @param currentSnapshot The current route snapshot up to this point in the matching process. While this parameter is optional,
* it will always be defined when called by the Router. It is only optional for backwards compatibility with functions defined prior
* to the introduction of this parameter.
* @param currentSnapshot The current route snapshot up to this point in the matching process.
*
* @publicApi
* @see {@link Route}
Expand All @@ -1183,7 +1185,7 @@ export interface CanMatch {
export type CanMatchFn = (
route: Route,
segments: UrlSegment[],
currentSnapshot?: PartialMatchRouteSnapshot,
currentSnapshot: PartialMatchRouteSnapshot,
) => MaybeAsync<GuardResult>;

/**
Expand Down