Skip to content

Commit c57951d

Browse files
atscottthePunderWoman
authored andcommitted
fix(router): Remove 'any' type from route guards (angular#60378)
This commit removes `'any'` from the type union for router guards and replaces it with 'string', which will eventually also be removed. This change allows TypeScript to infer the parameter types of functions when using functional guards and enables stricter type-checking to ensure the guard array contains valid values. BREAKING CHANGE: The guards arrays on `Route` no longer include `any` in the type union. The union includes functions for the functional guards as well as a type matching `Injector.get`: `ProviderToken<T>|string`. Note that string is still deprecated on both the route guards and `Injector.get`. PR Close angular#60378
1 parent 0fedf2c commit c57951d

File tree

4 files changed

+37
-21
lines changed

4 files changed

+37
-21
lines changed

goldens/public-api/router/index.api.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,10 @@ export class DefaultUrlSerializer implements UrlSerializer {
244244
}
245245

246246
// @public @deprecated
247-
export type DeprecatedGuard = ProviderToken<any> | any;
247+
export type DeprecatedGuard = ProviderToken<any> | string;
248+
249+
// @public @deprecated
250+
export type DeprecatedResolve = DeprecatedGuard | any;
248251

249252
// @public
250253
export type DetachedRouteHandle = {};
@@ -611,7 +614,7 @@ export interface Resolve<T> {
611614

612615
// @public
613616
export type ResolveData = {
614-
[key: string | symbol]: ResolveFn<unknown> | DeprecatedGuard;
617+
[key: string | symbol]: ResolveFn<unknown> | DeprecatedResolve;
615618
};
616619

617620
// @public

packages/router/src/models.ts

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ import type {UrlSegment, UrlSegmentGroup, UrlTree} from './url_tree';
4646
export type OnSameUrlNavigation = 'reload' | 'ignore';
4747

4848
/**
49-
* The `InjectionToken` and `@Injectable` classes for guards and resolvers are deprecated in favor
49+
* The `InjectionToken` and `@Injectable` classes for guards are deprecated in favor
5050
* of plain JavaScript functions instead. Dependency injection can still be achieved using the
5151
* [`inject`](api/core/inject) function from `@angular/core` and an injectable class can be used as
5252
* a functional guard using [`inject`](api/core/inject): `canActivate: [() =>
@@ -58,11 +58,23 @@ export type OnSameUrlNavigation = 'reload' | 'ignore';
5858
* @see {@link CanActivateFn}
5959
* @see {@link CanActivateChildFn}
6060
* @see {@link CanDeactivateFn}
61+
* @see {@link /api/core/inject inject}
62+
* @publicApi
63+
*/
64+
export type DeprecatedGuard = ProviderToken<any> | string;
65+
66+
/**
67+
* The `InjectionToken` and `@Injectable` classes for resolvers are deprecated in favor
68+
* of plain JavaScript functions instead. Dependency injection can still be achieved using the
69+
* [`inject`](api/core/inject) function from `@angular/core` and an injectable class can be used as
70+
* a functional guard using [`inject`](api/core/inject): `myResolvedData: () => inject(MyResolver).resolve()`.
71+
*
72+
* @deprecated
6173
* @see {@link ResolveFn}
6274
* @see {@link /api/core/inject inject}
6375
* @publicApi
6476
*/
65-
export type DeprecatedGuard = ProviderToken<any> | any;
77+
export type DeprecatedResolve = DeprecatedGuard | any;
6678

6779
/**
6880
* The supported types that can be returned from a `Router` guard.
@@ -197,7 +209,7 @@ export type Data = {
197209
* @publicApi
198210
*/
199211
export type ResolveData = {
200-
[key: string | symbol]: ResolveFn<unknown> | DeprecatedGuard;
212+
[key: string | symbol]: ResolveFn<unknown> | DeprecatedResolve;
201213
};
202214

203215
/**

packages/router/src/models_deprecated.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,4 @@
1010
// The public API re-exports everything from this file, which can be patched
1111
// locally in g3 to prevent regressions after cleanups complete.
1212

13-
export {DeprecatedGuard} from './models';
13+
export {DeprecatedGuard, DeprecatedResolve} from './models';

packages/router/src/operators/check_guards.ts

Lines changed: 16 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -163,20 +163,21 @@ function runCanActivate(
163163
const canActivate = futureARS.routeConfig ? futureARS.routeConfig.canActivate : null;
164164
if (!canActivate || canActivate.length === 0) return of(true);
165165

166-
const canActivateObservables = canActivate.map(
167-
(canActivate: CanActivateFn | ProviderToken<unknown>) => {
168-
return defer(() => {
169-
const closestInjector = getClosestRouteInjector(futureARS) ?? injector;
170-
const guard = getTokenOrFunctionIdentity<CanActivate>(canActivate, closestInjector);
171-
const guardVal = isCanActivate(guard)
172-
? guard.canActivate(futureARS, futureRSS)
173-
: runInInjectionContext(closestInjector, () =>
174-
(guard as CanActivateFn)(futureARS, futureRSS),
175-
);
176-
return wrapIntoObservable(guardVal).pipe(first());
177-
});
178-
},
179-
);
166+
const canActivateObservables = canActivate.map((canActivate) => {
167+
return defer(() => {
168+
const closestInjector = getClosestRouteInjector(futureARS) ?? injector;
169+
const guard = getTokenOrFunctionIdentity<CanActivate>(
170+
canActivate as ProviderToken<CanActivate>,
171+
closestInjector,
172+
);
173+
const guardVal = isCanActivate(guard)
174+
? guard.canActivate(futureARS, futureRSS)
175+
: runInInjectionContext(closestInjector, () =>
176+
(guard as CanActivateFn)(futureARS, futureRSS),
177+
);
178+
return wrapIntoObservable(guardVal).pipe(first());
179+
});
180+
});
180181
return of(canActivateObservables).pipe(prioritizedGuardValue());
181182
}
182183

@@ -281,7 +282,7 @@ export function runCanMatchGuards(
281282
if (!canMatch || canMatch.length === 0) return of(true);
282283

283284
const canMatchObservables = canMatch.map((injectionToken) => {
284-
const guard = getTokenOrFunctionIdentity(injectionToken, injector);
285+
const guard = getTokenOrFunctionIdentity(injectionToken as ProviderToken<any>, injector);
285286
const guardVal = isCanMatch(guard)
286287
? guard.canMatch(route, segments)
287288
: runInInjectionContext(injector, () => (guard as CanMatchFn)(route, segments));

0 commit comments

Comments
 (0)