refactor(router): Adjust type of parameter in navigateByUrl and createUrlTree to be more accurate (#38227)

`router.navigateByUrl` and `router.createUrlTree` only use a subset of the `NavigationExtras`. This commit
changes the parameter type to use new interfaces that only specify the properties used by
those function implementations. `NavigationExtras` extends both of those interfaces.

Fixes #18798

BREAKING CHANGE: While the new parameter types allow a variable of type
`NavigationExtras` to be passed in, they will not allow object literals,
as they may only specify known properties. They will also not accept
types that do not have properties in common with the ones in the `Pick`.
To fix this error, only specify properties from the `NavigationExtras` which are
actually used in the respective function calls or use a type assertion
on the object or variable: `as NavigationExtras`.

PR Close #38227
This commit is contained in:
Andrew Scott 2020-07-24 13:39:56 -07:00 committed by Alex Rickabaugh
parent 837889f0a4
commit e4f4d18e7e
6 changed files with 118 additions and 63 deletions

View File

@ -122,7 +122,7 @@ Tip: In the [API reference section](api) of this doc site, deprecated APIs are i
| API | Replacement | Deprecation announced | Notes |
| --- | ----------- | --------------------- | ----- |
| [`preserveQueryParams`](api/router/NavigationExtras#preserveQueryParams) | [`queryParamsHandling`](api/router/NavigationExtras#queryParamsHandling) | v4 | none |
| [`preserveQueryParams`](api/router/UrlCreationOptions#preserveQueryParams) | [`queryParamsHandling`](api/router/UrlCreationOptions#queryParamsHandling) | v4 | none |
{@a platform-webworker}
### @angular/platform-webworker

View File

@ -172,6 +172,14 @@ export declare type Navigation = {
previousNavigation: Navigation | null;
};
export declare interface NavigationBehaviorOptions {
replaceUrl?: boolean;
skipLocationChange?: boolean;
state?: {
[k: string]: any;
};
}
export declare class NavigationCancel extends RouterEvent {
reason: string;
constructor(
@ -199,18 +207,7 @@ export declare class NavigationError extends RouterEvent {
toString(): string;
}
export declare interface NavigationExtras {
fragment?: string;
preserveFragment?: boolean;
/** @deprecated */ preserveQueryParams?: boolean;
queryParams?: Params | null;
queryParamsHandling?: QueryParamsHandling | null;
relativeTo?: ActivatedRoute | null;
replaceUrl?: boolean;
skipLocationChange?: boolean;
state?: {
[k: string]: any;
};
export declare interface NavigationExtras extends UrlCreationOptions, NavigationBehaviorOptions {
}
export declare class NavigationStart extends RouterEvent {
@ -344,13 +341,13 @@ export declare class Router {
urlHandlingStrategy: UrlHandlingStrategy;
urlUpdateStrategy: 'deferred' | 'eager';
constructor(rootComponentType: Type<any> | null, urlSerializer: UrlSerializer, rootContexts: ChildrenOutletContexts, location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler, config: Routes);
createUrlTree(commands: any[], navigationExtras?: NavigationExtras): UrlTree;
createUrlTree(commands: any[], navigationExtras?: UrlCreationOptions): UrlTree;
dispose(): void;
getCurrentNavigation(): Navigation | null;
initialNavigation(): void;
isActive(url: string | UrlTree, exact: boolean): boolean;
navigate(commands: any[], extras?: NavigationExtras): Promise<boolean>;
navigateByUrl(url: string | UrlTree, extras?: NavigationExtras): Promise<boolean>;
navigateByUrl(url: string | UrlTree, extras?: NavigationBehaviorOptions): Promise<boolean>;
ngOnDestroy(): void;
parseUrl(url: string): UrlTree;
resetConfig(config: Routes): void;
@ -502,6 +499,15 @@ export declare class Scroll {
toString(): string;
}
export declare interface UrlCreationOptions {
fragment?: string;
preserveFragment?: boolean;
/** @deprecated */ preserveQueryParams?: boolean;
queryParams?: Params | null;
queryParamsHandling?: QueryParamsHandling | null;
relativeTo?: ActivatedRoute | null;
}
export declare abstract class UrlHandlingStrategy {
abstract extract(url: UrlTree): UrlTree;
abstract merge(newUrlPart: UrlTree, rawUrl: UrlTree): UrlTree;

View File

@ -140,7 +140,7 @@ export type DeprecatedLoadChildren = string;
* - `merge` : Merge new with current parameters.
* - `preserve` : Preserve current parameters.
*
* @see `NavigationExtras#queryParamsHandling`
* @see `UrlCreationOptions#queryParamsHandling`
* @see `RouterLink`
* @publicApi
*/

View File

@ -84,7 +84,7 @@ import {UrlTree} from '../url_tree';
* </a>
* ```
*
* See {@link NavigationExtras.queryParamsHandling NavigationExtras#queryParamsHandling}.
* See {@link UrlCreationOptions.queryParamsHandling UrlCreationOptions#queryParamsHandling}.
*
* ### Preserving navigation history
*
@ -117,51 +117,58 @@ import {UrlTree} from '../url_tree';
@Directive({selector: ':not(a):not(area)[routerLink]'})
export class RouterLink implements OnChanges {
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#queryParams NavigationExtras#queryParams}
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the
* `UrlCreationOptions`.
* @see {@link UrlCreationOptions#queryParams UrlCreationOptions#queryParams}
* @see {@link Router#createUrlTree Router#createUrlTree}
*/
// TODO(issue/24571): remove '!'.
@Input() queryParams!: {[k: string]: any};
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#fragment NavigationExtras#fragment}
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the
* `UrlCreationOptions`.
* @see {@link UrlCreationOptions#fragment UrlCreationOptions#fragment}
* @see {@link Router#createUrlTree Router#createUrlTree}
*/
// TODO(issue/24571): remove '!'.
@Input() fragment!: string;
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#queryParamsHandling NavigationExtras#queryParamsHandling}
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the
* `UrlCreationOptions`.
* @see {@link UrlCreationOptions#queryParamsHandling UrlCreationOptions#queryParamsHandling}
* @see {@link Router#createUrlTree Router#createUrlTree}
*/
// TODO(issue/24571): remove '!'.
@Input() queryParamsHandling!: QueryParamsHandling;
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#preserveFragment NavigationExtras#preserveFragment}
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the
* `UrlCreationOptions`.
* @see {@link UrlCreationOptions#preserveFragment UrlCreationOptions#preserveFragment}
* @see {@link Router#createUrlTree Router#createUrlTree}
*/
// TODO(issue/24571): remove '!'.
@Input() preserveFragment!: boolean;
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#skipLocationChange NavigationExtras#skipLocationChange}
* @see {@link Router#createUrlTree Router#createUrlTree}
* Passed to {@link Router#navigateByUrl Router#navigateByUrl} as part of the
* `NavigationBehaviorOptions`.
* @see {@link NavigationBehaviorOptions#skipLocationChange NavigationBehaviorOptions#skipLocationChange}
* @see {@link Router#navigateByUrl Router#navigateByUrl}
*/
// TODO(issue/24571): remove '!'.
@Input() skipLocationChange!: boolean;
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#replaceUrl NavigationExtras#replaceUrl}
* @see {@link Router#createUrlTree Router#createUrlTree}
* Passed to {@link Router#navigateByUrl Router#navigateByUrl} as part of the
* `NavigationBehaviorOptions`.
* @see {@link NavigationBehaviorOptions#replaceUrl NavigationBehaviorOptions#replaceUrl}
* @see {@link Router#navigateByUrl Router#navigateByUrl}
*/
// TODO(issue/24571): remove '!'.
@Input() replaceUrl!: boolean;
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#state NavigationExtras#state}
* @see {@link Router#createUrlTree Router#createUrlTree}
* Passed to {@link Router#navigateByUrl Router#navigateByUrl} as part of the
* `NavigationBehaviorOptions`.
* @see {@link NavigationBehaviorOptions#state NavigationBehaviorOptions#state}
* @see {@link Router#navigateByUrl Router#navigateByUrl}
*/
@Input() state?: {[k: string]: any};
private commands: any[] = [];
@ -252,51 +259,58 @@ export class RouterLinkWithHref implements OnChanges, OnDestroy {
// TODO(issue/24571): remove '!'.
@HostBinding('attr.target') @Input() target!: string;
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#queryParams NavigationExtras#queryParams}
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the
* `UrlCreationOptions`.
* @see {@link UrlCreationOptions#queryParams UrlCreationOptions#queryParams}
* @see {@link Router#createUrlTree Router#createUrlTree}
*/
// TODO(issue/24571): remove '!'.
@Input() queryParams!: {[k: string]: any};
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#fragment NavigationExtras#fragment}
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the
* `UrlCreationOptions`.
* @see {@link UrlCreationOptions#fragment UrlCreationOptions#fragment}
* @see {@link Router#createUrlTree Router#createUrlTree}
*/
// TODO(issue/24571): remove '!'.
@Input() fragment!: string;
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#queryParamsHandling NavigationExtras#queryParamsHandling}
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the
* `UrlCreationOptions`.
* @see {@link UrlCreationOptions#queryParamsHandling UrlCreationOptions#queryParamsHandling}
* @see {@link Router#createUrlTree Router#createUrlTree}
*/
// TODO(issue/24571): remove '!'.
@Input() queryParamsHandling!: QueryParamsHandling;
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#preserveFragment NavigationExtras#preserveFragment}
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the
* `UrlCreationOptions`.
* @see {@link UrlCreationOptions#preserveFragment UrlCreationOptions#preserveFragment}
* @see {@link Router#createUrlTree Router#createUrlTree}
*/
// TODO(issue/24571): remove '!'.
@Input() preserveFragment!: boolean;
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#skipLocationChange NavigationExtras#skipLocationChange}
* @see {@link Router#createUrlTree Router#createUrlTree}
* Passed to {@link Router#navigateByUrl Router#navigateByUrl} as part of the
* `NavigationBehaviorOptions`.
* @see {@link NavigationBehaviorOptions#skipLocationChange NavigationBehaviorOptions#skipLocationChange}
* @see {@link Router#navigateByUrl Router#navigateByUrl}
*/
// TODO(issue/24571): remove '!'.
@Input() skipLocationChange!: boolean;
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#replaceUrl NavigationExtras#replaceUrl}
* @see {@link Router#createUrlTree Router#createUrlTree}
* Passed to {@link Router#navigateByUrl Router#navigateByUrl} as part of the
* `NavigationBehaviorOptions`.
* @see {@link NavigationBehaviorOptions#replaceUrl NavigationBehaviorOptions#replaceUrl}
* @see {@link Router#navigateByUrl Router#navigateByUrl}
*/
// TODO(issue/24571): remove '!'.
@Input() replaceUrl!: boolean;
/**
* Passed to {@link Router#createUrlTree Router#createUrlTree} as part of the `NavigationExtras`.
* @see {@link NavigationExtras#state NavigationExtras#state}
* @see {@link Router#createUrlTree Router#createUrlTree}
* Passed to {@link Router#navigateByUrl Router#navigateByUrl} as part of the
* `NavigationBehaviorOptions`.
* @see {@link NavigationBehaviorOptions#state NavigationBehaviorOptions#state}
* @see {@link Router#navigateByUrl Router#navigateByUrl}
*/
@Input() state?: {[k: string]: any};
private commands: any[] = [];

View File

@ -14,7 +14,7 @@ export {RouterOutlet} from './directives/router_outlet';
export {ActivationEnd, ActivationStart, ChildActivationEnd, ChildActivationStart, Event, GuardsCheckEnd, GuardsCheckStart, NavigationCancel, NavigationEnd, NavigationError, NavigationStart, ResolveEnd, ResolveStart, RouteConfigLoadEnd, RouteConfigLoadStart, RouterEvent, RoutesRecognized, Scroll} from './events';
export {CanActivate, CanActivateChild, CanDeactivate, CanLoad, Resolve} from './interfaces';
export {BaseRouteReuseStrategy, DetachedRouteHandle, RouteReuseStrategy} from './route_reuse_strategy';
export {Navigation, NavigationExtras, Router} from './router';
export {Navigation, NavigationBehaviorOptions, NavigationExtras, Router, UrlCreationOptions} from './router';
export {ROUTES} from './router_config_loader';
export {ExtraOptions, InitialNavigation, provideRoutes, ROUTER_CONFIGURATION, ROUTER_INITIALIZER, RouterModule} from './router_module';
export {ChildrenOutletContexts, OutletContext} from './router_outlet_context';

View File

@ -33,21 +33,21 @@ import {Checks, getAllRouteGuards} from './utils/preactivation';
import {isUrlTree} from './utils/type_guards';
/**
* @description
*
* Options that modify the `Router` navigation strategy.
* Options that modify the `Router` URL.
* Supply an object containing any of these properties to a `Router` navigation function to
* control how the target URL should be constructed or interpreted.
* control how the target URL should be constructed.
*
* @see [Router.navigate() method](api/router/Router#navigate)
* @see [Router.navigateByUrl() method](api/router/Router#navigatebyurl)
* @see [Router.createUrlTree() method](api/router/Router#createurltree)
* @see [Routing and Navigation guide](guide/router)
*
* @publicApi
*/
export interface NavigationExtras {
export interface UrlCreationOptions {
/**
* Specifies a root URI to use for relative navigation.
*
@ -135,6 +135,7 @@ export interface NavigationExtras {
*
*/
queryParamsHandling?: QueryParamsHandling|null;
/**
* When true, preserves the URL fragment for the next navigation
*
@ -144,6 +145,22 @@ export interface NavigationExtras {
* ```
*/
preserveFragment?: boolean;
}
/**
* @description
*
* Options that modify the `Router` navigation strategy.
* Supply an object containing any of these properties to a `Router` navigation function to
* control how the navigation should be handled.
*
* @see [Router.navigate() method](api/router/Router#navigate)
* @see [Router.navigateByUrl() method](api/router/Router#navigatebyurl)
* @see [Routing and Navigation guide](guide/router)
*
* @publicApi
*/
export interface NavigationBehaviorOptions {
/**
* When true, navigates without pushing a new state into history.
*
@ -153,6 +170,7 @@ export interface NavigationExtras {
* ```
*/
skipLocationChange?: boolean;
/**
* When true, navigates while replacing the current state in history.
*
@ -162,6 +180,7 @@ export interface NavigationExtras {
* ```
*/
replaceUrl?: boolean;
/**
* Developer-defined state that can be passed to any navigation.
* Access this value through the `Navigation.extras` object
@ -180,6 +199,24 @@ export interface NavigationExtras {
state?: {[k: string]: any};
}
/**
* @description
*
* Options that modify the `Router` navigation strategy.
* Supply an object containing any of these properties to a `Router` navigation function to
* control how the target URL should be constructed or interpreted.
*
* @see [Router.navigate() method](api/router/Router#navigate)
* @see [Router.navigateByUrl() method](api/router/Router#navigatebyurl)
* @see [Router.createUrlTree() method](api/router/Router#createurltree)
* @see [Routing and Navigation guide](guide/router)
* @see UrlCreationOptions
* @see NavigationBehaviorOptions
*
* @publicApi
*/
export interface NavigationExtras extends UrlCreationOptions, NavigationBehaviorOptions {}
/**
* Error handler that is invoked when a navigation error occurs.
*
@ -1030,8 +1067,7 @@ export class Router {
* segments, followed by the parameters for each segment.
* The fragments are applied to the current URL tree or the one provided in the `relativeTo`
* property of the options object, if supplied.
* @param navigationExtras Options that control the navigation strategy. This function
* only uses properties in `NavigationExtras` that would change the provided URL.
* @param navigationExtras Options that control the navigation strategy.
* @returns The new URL tree.
*
* @usageNotes
@ -1068,7 +1104,7 @@ export class Router {
* router.createUrlTree(['../../team/44/user/22'], {relativeTo: route});
* ```
*/
createUrlTree(commands: any[], navigationExtras: NavigationExtras = {}): UrlTree {
createUrlTree(commands: any[], navigationExtras: UrlCreationOptions = {}): UrlTree {
const {
relativeTo,
queryParams,
@ -1110,8 +1146,6 @@ export class Router {
* @param url An absolute path for a defined route. The function does not apply any delta to the
* current URL.
* @param extras An object containing properties that modify the navigation strategy.
* The function ignores any properties in the `NavigationExtras` that would change the
* provided URL.
*
* @returns A Promise that resolves to 'true' when navigation succeeds,
* to 'false' when navigation fails, or is rejected on error.
@ -1130,8 +1164,9 @@ export class Router {
* @see [Routing and Navigation guide](guide/router)
*
*/
navigateByUrl(url: string|UrlTree, extras: NavigationExtras = {skipLocationChange: false}):
Promise<boolean> {
navigateByUrl(url: string|UrlTree, extras: NavigationBehaviorOptions = {
skipLocationChange: false
}): Promise<boolean> {
if (typeof ngDevMode === 'undefined' ||
ngDevMode && this.isNgZoneEnabled && !NgZone.isInAngularZone()) {
this.console.warn(