fix: argument destructuring sometimes breaks strictNullChecks

Destructuring of the form:

function foo({a, b}: {a?, b?} = {})

breaks strictNullChecks, due to the TypeScript bug https://github.com/microsoft/typescript/issues/10078.
This change eliminates usage of destructuring in function argument lists in cases where it would leak
into the public API .d.ts.
This commit is contained in:
Alex Rickabaugh 2017-06-12 10:59:29 -07:00 committed by Hans
parent 009651e14f
commit c59c390cdc
8 changed files with 91 additions and 97 deletions

View File

@ -13,16 +13,15 @@ export enum NumberFormatStyle {
} }
export class NumberFormatter { export class NumberFormatter {
static format( static format(num: number, locale: string, style: NumberFormatStyle, opts: {
num: number, locale: string, style: NumberFormatStyle,
{minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits, currency,
currencyAsSymbol = false}: {
minimumIntegerDigits?: number, minimumIntegerDigits?: number,
minimumFractionDigits?: number, minimumFractionDigits?: number,
maximumFractionDigits?: number, maximumFractionDigits?: number,
currency?: string|null, currency?: string|null,
currencyAsSymbol?: boolean currencyAsSymbol?: boolean
} = {}): string { } = {}): string {
const {minimumIntegerDigits, minimumFractionDigits, maximumFractionDigits, currency,
currencyAsSymbol = false} = opts;
const options: Intl.NumberFormatOptions = { const options: Intl.NumberFormatOptions = {
minimumIntegerDigits, minimumIntegerDigits,
minimumFractionDigits, minimumFractionDigits,

View File

@ -183,11 +183,8 @@ export interface ContentChildrenDecorator {
* @stable * @stable
* @Annotation * @Annotation
*/ */
(selector: Type<any>|Function|string, (selector: Type<any>|Function|string, opts?: {descendants?: boolean, read?: any}): any;
{descendants, read}?: {descendants?: boolean, read?: any}): any; new (selector: Type<any>|Function|string, opts?: {descendants?: boolean, read?: any}): Query;
new (
selector: Type<any>|Function|string,
{descendants, read}?: {descendants?: boolean, read?: any}): Query;
} }
/** /**
@ -247,8 +244,8 @@ export interface ContentChildDecorator {
* @stable * @stable
* @Annotation * @Annotation
*/ */
(selector: Type<any>|Function|string, {read}?: {read?: any}): any; (selector: Type<any>|Function|string, opts?: {read?: any}): any;
new (selector: Type<any>|Function|string, {read}?: {read?: any}): ContentChild; new (selector: Type<any>|Function|string, opts?: {read?: any}): ContentChild;
} }
/** /**
@ -308,8 +305,8 @@ export interface ViewChildrenDecorator {
* @stable * @stable
* @Annotation * @Annotation
*/ */
(selector: Type<any>|Function|string, {read}?: {read?: any}): any; (selector: Type<any>|Function|string, opts?: {read?: any}): any;
new (selector: Type<any>|Function|string, {read}?: {read?: any}): ViewChildren; new (selector: Type<any>|Function|string, opts?: {read?: any}): ViewChildren;
} }
/** /**
@ -365,8 +362,8 @@ export interface ViewChildDecorator {
* @stable * @stable
* @Annotation * @Annotation
*/ */
(selector: Type<any>|Function|string, {read}?: {read?: any}): any; (selector: Type<any>|Function|string, opts?: {read?: any}): any;
new (selector: Type<any>|Function|string, {read}?: {read?: any}): ViewChild; new (selector: Type<any>|Function|string, opts?: {read?: any}): ViewChild;
} }
/** /**

View File

@ -76,8 +76,7 @@ export class ViewMetadata {
/** {@link Component#interpolation} */ /** {@link Component#interpolation} */
interpolation: [string, string]|undefined; interpolation: [string, string]|undefined;
constructor( constructor(opts: {
{templateUrl, template, encapsulation, styles, styleUrls, animations, interpolation}: {
templateUrl?: string, templateUrl?: string,
template?: string, template?: string,
encapsulation?: ViewEncapsulation, encapsulation?: ViewEncapsulation,
@ -86,12 +85,12 @@ export class ViewMetadata {
animations?: any[], animations?: any[],
interpolation?: [string, string] interpolation?: [string, string]
} = {}) { } = {}) {
this.templateUrl = templateUrl; this.templateUrl = opts.templateUrl;
this.template = template; this.template = opts.template;
this.styleUrls = styleUrls; this.styleUrls = opts.styleUrls;
this.styles = styles; this.styles = opts.styles;
this.encapsulation = encapsulation; this.encapsulation = opts.encapsulation;
this.animations = animations; this.animations = opts.animations;
this.interpolation = interpolation; this.interpolation = opts.interpolation;
} }
} }

View File

@ -238,11 +238,11 @@ export abstract class AbstractControl {
* This will also mark all direct ancestors as `touched` to maintain * This will also mark all direct ancestors as `touched` to maintain
* the model. * the model.
*/ */
markAsTouched({onlySelf}: {onlySelf?: boolean} = {}): void { markAsTouched(opts: {onlySelf?: boolean} = {}): void {
this._touched = true; this._touched = true;
if (this._parent && !onlySelf) { if (this._parent && !opts.onlySelf) {
this._parent.markAsTouched({onlySelf}); this._parent.markAsTouched(opts);
} }
} }
@ -253,14 +253,14 @@ export abstract class AbstractControl {
* to maintain the model, and re-calculate the `touched` status of all parent * to maintain the model, and re-calculate the `touched` status of all parent
* controls. * controls.
*/ */
markAsUntouched({onlySelf}: {onlySelf?: boolean} = {}): void { markAsUntouched(opts: {onlySelf?: boolean} = {}): void {
this._touched = false; this._touched = false;
this._forEachChild( this._forEachChild(
(control: AbstractControl) => { control.markAsUntouched({onlySelf: true}); }); (control: AbstractControl) => { control.markAsUntouched({onlySelf: true}); });
if (this._parent && !onlySelf) { if (this._parent && !opts.onlySelf) {
this._parent._updateTouched({onlySelf}); this._parent._updateTouched(opts);
} }
} }
@ -270,11 +270,11 @@ export abstract class AbstractControl {
* This will also mark all direct ancestors as `dirty` to maintain * This will also mark all direct ancestors as `dirty` to maintain
* the model. * the model.
*/ */
markAsDirty({onlySelf}: {onlySelf?: boolean} = {}): void { markAsDirty(opts: {onlySelf?: boolean} = {}): void {
this._pristine = false; this._pristine = false;
if (this._parent && !onlySelf) { if (this._parent && !opts.onlySelf) {
this._parent.markAsDirty({onlySelf}); this._parent.markAsDirty(opts);
} }
} }
@ -285,24 +285,24 @@ export abstract class AbstractControl {
* to maintain the model, and re-calculate the `pristine` status of all parent * to maintain the model, and re-calculate the `pristine` status of all parent
* controls. * controls.
*/ */
markAsPristine({onlySelf}: {onlySelf?: boolean} = {}): void { markAsPristine(opts: {onlySelf?: boolean} = {}): void {
this._pristine = true; this._pristine = true;
this._forEachChild((control: AbstractControl) => { control.markAsPristine({onlySelf: true}); }); this._forEachChild((control: AbstractControl) => { control.markAsPristine({onlySelf: true}); });
if (this._parent && !onlySelf) { if (this._parent && !opts.onlySelf) {
this._parent._updatePristine({onlySelf}); this._parent._updatePristine(opts);
} }
} }
/** /**
* Marks the control as `pending`. * Marks the control as `pending`.
*/ */
markAsPending({onlySelf}: {onlySelf?: boolean} = {}): void { markAsPending(opts: {onlySelf?: boolean} = {}): void {
this._status = PENDING; this._status = PENDING;
if (this._parent && !onlySelf) { if (this._parent && !opts.onlySelf) {
this._parent.markAsPending({onlySelf}); this._parent.markAsPending(opts);
} }
} }
@ -312,18 +312,18 @@ export abstract class AbstractControl {
* *
* If the control has children, all children will be disabled to maintain the model. * If the control has children, all children will be disabled to maintain the model.
*/ */
disable({onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { disable(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
this._status = DISABLED; this._status = DISABLED;
this._errors = null; this._errors = null;
this._forEachChild((control: AbstractControl) => { control.disable({onlySelf: true}); }); this._forEachChild((control: AbstractControl) => { control.disable({onlySelf: true}); });
this._updateValue(); this._updateValue();
if (emitEvent !== false) { if (opts.emitEvent !== false) {
this._valueChanges.emit(this._value); this._valueChanges.emit(this._value);
this._statusChanges.emit(this._status); this._statusChanges.emit(this._status);
} }
this._updateAncestors(!!onlySelf); this._updateAncestors(!!opts.onlySelf);
this._onDisabledChange.forEach((changeFn) => changeFn(true)); this._onDisabledChange.forEach((changeFn) => changeFn(true));
} }
@ -334,12 +334,12 @@ export abstract class AbstractControl {
* *
* If the control has children, all children will be enabled. * If the control has children, all children will be enabled.
*/ */
enable({onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): void { enable(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
this._status = VALID; this._status = VALID;
this._forEachChild((control: AbstractControl) => { control.enable({onlySelf: true}); }); this._forEachChild((control: AbstractControl) => { control.enable({onlySelf: true}); });
this.updateValueAndValidity({onlySelf: true, emitEvent}); this.updateValueAndValidity({onlySelf: true, emitEvent: opts.emitEvent});
this._updateAncestors(!!onlySelf); this._updateAncestors(!!opts.onlySelf);
this._onDisabledChange.forEach((changeFn) => changeFn(false)); this._onDisabledChange.forEach((changeFn) => changeFn(false));
} }
@ -373,8 +373,7 @@ export abstract class AbstractControl {
* *
* By default, it will also update the value and validity of its ancestors. * By default, it will also update the value and validity of its ancestors.
*/ */
updateValueAndValidity({onlySelf, emitEvent}: {onlySelf?: boolean, emitEvent?: boolean} = {}): updateValueAndValidity(opts: {onlySelf?: boolean, emitEvent?: boolean} = {}): void {
void {
this._setInitialStatus(); this._setInitialStatus();
this._updateValue(); this._updateValue();
@ -384,24 +383,24 @@ export abstract class AbstractControl {
this._status = this._calculateStatus(); this._status = this._calculateStatus();
if (this._status === VALID || this._status === PENDING) { if (this._status === VALID || this._status === PENDING) {
this._runAsyncValidator(emitEvent); this._runAsyncValidator(opts.emitEvent);
} }
} }
if (emitEvent !== false) { if (opts.emitEvent !== false) {
this._valueChanges.emit(this._value); this._valueChanges.emit(this._value);
this._statusChanges.emit(this._status); this._statusChanges.emit(this._status);
} }
if (this._parent && !onlySelf) { if (this._parent && !opts.onlySelf) {
this._parent.updateValueAndValidity({onlySelf, emitEvent}); this._parent.updateValueAndValidity(opts);
} }
} }
/** @internal */ /** @internal */
_updateTreeValidity({emitEvent}: {emitEvent?: boolean} = {emitEvent: true}) { _updateTreeValidity(opts: {emitEvent?: boolean} = {emitEvent: true}) {
this._forEachChild((ctrl: AbstractControl) => ctrl._updateTreeValidity({emitEvent})); this._forEachChild((ctrl: AbstractControl) => ctrl._updateTreeValidity(opts));
this.updateValueAndValidity({onlySelf: true, emitEvent}); this.updateValueAndValidity({onlySelf: true, emitEvent: opts.emitEvent});
} }
private _setInitialStatus() { this._status = this._allControlsDisabled() ? DISABLED : VALID; } private _setInitialStatus() { this._status = this._allControlsDisabled() ? DISABLED : VALID; }
@ -448,9 +447,9 @@ export abstract class AbstractControl {
* expect(login.valid).toEqual(true); * expect(login.valid).toEqual(true);
* ``` * ```
*/ */
setErrors(errors: ValidationErrors|null, {emitEvent}: {emitEvent?: boolean} = {}): void { setErrors(errors: ValidationErrors|null, opts: {emitEvent?: boolean} = {}): void {
this._errors = errors; this._errors = errors;
this._updateControlsErrors(emitEvent !== false); this._updateControlsErrors(opts.emitEvent !== false);
} }
/** /**
@ -556,20 +555,20 @@ export abstract class AbstractControl {
} }
/** @internal */ /** @internal */
_updatePristine({onlySelf}: {onlySelf?: boolean} = {}): void { _updatePristine(opts: {onlySelf?: boolean} = {}): void {
this._pristine = !this._anyControlsDirty(); this._pristine = !this._anyControlsDirty();
if (this._parent && !onlySelf) { if (this._parent && !opts.onlySelf) {
this._parent._updatePristine({onlySelf}); this._parent._updatePristine(opts);
} }
} }
/** @internal */ /** @internal */
_updateTouched({onlySelf}: {onlySelf?: boolean} = {}): void { _updateTouched(opts: {onlySelf?: boolean} = {}): void {
this._touched = this._anyControlsTouched(); this._touched = this._anyControlsTouched();
if (this._parent && !onlySelf) { if (this._parent && !opts.onlySelf) {
this._parent._updateTouched({onlySelf}); this._parent._updateTouched(opts);
} }
} }

View File

@ -385,9 +385,9 @@ export class Router {
* router.createUrlTree(['../../team/44/user/22'], {relativeTo: route}); * router.createUrlTree(['../../team/44/user/22'], {relativeTo: route});
* ``` * ```
*/ */
createUrlTree( createUrlTree(commands: any[], navigationExtras: NavigationExtras = {}): UrlTree {
commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams, queryParamsHandling, const {relativeTo, queryParams, fragment,
preserveFragment}: NavigationExtras = {}): UrlTree { preserveQueryParams, queryParamsHandling, preserveFragment} = navigationExtras;
if (isDevMode() && preserveQueryParams && <any>console && <any>console.warn) { if (isDevMode() && preserveQueryParams && <any>console && <any>console.warn) {
console.warn('preserveQueryParams is deprecated, use queryParamsHandling instead.'); console.warn('preserveQueryParams is deprecated, use queryParamsHandling instead.');
} }

View File

@ -262,10 +262,10 @@ export declare const ContentChild: ContentChildDecorator;
/** @stable */ /** @stable */
export interface ContentChildDecorator { export interface ContentChildDecorator {
/** @stable */ (selector: Type<any> | Function | string, {read}?: { /** @stable */ (selector: Type<any> | Function | string, opts?: {
read?: any; read?: any;
}): any; }): any;
new (selector: Type<any> | Function | string, {read}?: { new (selector: Type<any> | Function | string, opts?: {
read?: any; read?: any;
}): ContentChild; }): ContentChild;
} }
@ -275,11 +275,11 @@ export declare const ContentChildren: ContentChildrenDecorator;
/** @stable */ /** @stable */
export interface ContentChildrenDecorator { export interface ContentChildrenDecorator {
/** @stable */ (selector: Type<any> | Function | string, {descendants, read}?: { /** @stable */ (selector: Type<any> | Function | string, opts?: {
descendants?: boolean; descendants?: boolean;
read?: any; read?: any;
}): any; }): any;
new (selector: Type<any> | Function | string, {descendants, read}?: { new (selector: Type<any> | Function | string, opts?: {
descendants?: boolean; descendants?: boolean;
read?: any; read?: any;
}): Query; }): Query;
@ -1058,10 +1058,10 @@ export declare const ViewChild: ViewChildDecorator;
/** @stable */ /** @stable */
export interface ViewChildDecorator { export interface ViewChildDecorator {
/** @stable */ (selector: Type<any> | Function | string, {read}?: { /** @stable */ (selector: Type<any> | Function | string, opts?: {
read?: any; read?: any;
}): any; }): any;
new (selector: Type<any> | Function | string, {read}?: { new (selector: Type<any> | Function | string, opts?: {
read?: any; read?: any;
}): ViewChild; }): ViewChild;
} }
@ -1071,10 +1071,10 @@ export declare const ViewChildren: ViewChildrenDecorator;
/** @stable */ /** @stable */
export interface ViewChildrenDecorator { export interface ViewChildrenDecorator {
/** @stable */ (selector: Type<any> | Function | string, {read}?: { /** @stable */ (selector: Type<any> | Function | string, opts?: {
read?: any; read?: any;
}): any; }): any;
new (selector: Type<any> | Function | string, {read}?: { new (selector: Type<any> | Function | string, opts?: {
read?: any; read?: any;
}): ViewChildren; }): ViewChildren;
} }

View File

@ -21,42 +21,42 @@ export declare abstract class AbstractControl {
constructor(validator: ValidatorFn | null, asyncValidator: AsyncValidatorFn | null); constructor(validator: ValidatorFn | null, asyncValidator: AsyncValidatorFn | null);
clearAsyncValidators(): void; clearAsyncValidators(): void;
clearValidators(): void; clearValidators(): void;
disable({onlySelf, emitEvent}?: { disable(opts?: {
onlySelf?: boolean; onlySelf?: boolean;
emitEvent?: boolean; emitEvent?: boolean;
}): void; }): void;
enable({onlySelf, emitEvent}?: { enable(opts?: {
onlySelf?: boolean; onlySelf?: boolean;
emitEvent?: boolean; emitEvent?: boolean;
}): void; }): void;
get(path: Array<string | number> | string): AbstractControl | null; get(path: Array<string | number> | string): AbstractControl | null;
getError(errorCode: string, path?: string[]): any; getError(errorCode: string, path?: string[]): any;
hasError(errorCode: string, path?: string[]): boolean; hasError(errorCode: string, path?: string[]): boolean;
markAsDirty({onlySelf}?: { markAsDirty(opts?: {
onlySelf?: boolean; onlySelf?: boolean;
}): void; }): void;
markAsPending({onlySelf}?: { markAsPending(opts?: {
onlySelf?: boolean; onlySelf?: boolean;
}): void; }): void;
markAsPristine({onlySelf}?: { markAsPristine(opts?: {
onlySelf?: boolean; onlySelf?: boolean;
}): void; }): void;
markAsTouched({onlySelf}?: { markAsTouched(opts?: {
onlySelf?: boolean; onlySelf?: boolean;
}): void; }): void;
markAsUntouched({onlySelf}?: { markAsUntouched(opts?: {
onlySelf?: boolean; onlySelf?: boolean;
}): void; }): void;
abstract patchValue(value: any, options?: Object): void; abstract patchValue(value: any, options?: Object): void;
abstract reset(value?: any, options?: Object): void; abstract reset(value?: any, options?: Object): void;
setAsyncValidators(newValidator: AsyncValidatorFn | AsyncValidatorFn[]): void; setAsyncValidators(newValidator: AsyncValidatorFn | AsyncValidatorFn[]): void;
setErrors(errors: ValidationErrors | null, {emitEvent}?: { setErrors(errors: ValidationErrors | null, opts?: {
emitEvent?: boolean; emitEvent?: boolean;
}): void; }): void;
setParent(parent: FormGroup | FormArray): void; setParent(parent: FormGroup | FormArray): void;
setValidators(newValidator: ValidatorFn | ValidatorFn[] | null): void; setValidators(newValidator: ValidatorFn | ValidatorFn[] | null): void;
abstract setValue(value: any, options?: Object): void; abstract setValue(value: any, options?: Object): void;
updateValueAndValidity({onlySelf, emitEvent}?: { updateValueAndValidity(opts?: {
onlySelf?: boolean; onlySelf?: boolean;
emitEvent?: boolean; emitEvent?: boolean;
}): void; }): void;

View File

@ -259,7 +259,7 @@ export declare class Router {
readonly url: string; readonly url: string;
urlHandlingStrategy: UrlHandlingStrategy; urlHandlingStrategy: UrlHandlingStrategy;
constructor(rootComponentType: Type<any> | null, urlSerializer: UrlSerializer, rootContexts: ChildrenOutletContexts, location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler, config: Routes); constructor(rootComponentType: Type<any> | null, urlSerializer: UrlSerializer, rootContexts: ChildrenOutletContexts, location: Location, injector: Injector, loader: NgModuleFactoryLoader, compiler: Compiler, config: Routes);
createUrlTree(commands: any[], {relativeTo, queryParams, fragment, preserveQueryParams, queryParamsHandling, preserveFragment}?: NavigationExtras): UrlTree; createUrlTree(commands: any[], navigationExtras?: NavigationExtras): UrlTree;
dispose(): void; dispose(): void;
initialNavigation(): void; initialNavigation(): void;
isActive(url: string | UrlTree, exact: boolean): boolean; isActive(url: string | UrlTree, exact: boolean): boolean;