Skip to content

Commit

Permalink
fix(material/core): update mixin functions to avoid unknown cast (#22577
Browse files Browse the repository at this point in the history
)

Reworks the mixin functions in order to remove a workaround where we had to cast to `unknown`. The cast was causing some issues with Closure compiler.

(cherry picked from commit d92f8f2)
  • Loading branch information
crisbeto authored and annieyw committed May 3, 2021
1 parent 0f0564b commit 33104b6
Show file tree
Hide file tree
Showing 9 changed files with 41 additions and 41 deletions.
3 changes: 2 additions & 1 deletion src/material-experimental/mdc-chips/chip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,8 @@ export class MatChipCssInternalOnly { }
* Boilerplate for applying mixins to MatChip.
* @docs-private
*/
class MatChipBase {
abstract class MatChipBase {
abstract disabled: boolean;
constructor(public _elementRef: ElementRef) {}
}

Expand Down
3 changes: 2 additions & 1 deletion src/material/chips/chip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ export const MAT_CHIP_TRAILING_ICON =

// Boilerplate for applying mixins to MatChip.
/** @docs-private */
class MatChipBase {
abstract class MatChipBase {
abstract disabled: boolean;
constructor(public _elementRef: ElementRef) {}
}

Expand Down
6 changes: 4 additions & 2 deletions src/material/core/common-behaviors/color.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* found in the LICENSE file at https://angular.io/license
*/

import {Constructor} from './constructor';
import {AbstractConstructor, Constructor} from './constructor';
import {ElementRef} from '@angular/core';

/** @docs-private */
Expand All @@ -19,7 +19,7 @@ export interface CanColor {
}

/** @docs-private */
export type CanColorCtor = Constructor<CanColor>;
export type CanColorCtor = Constructor<CanColor> & AbstractConstructor<CanColor>;

/** @docs-private */
export interface HasElementRef {
Expand All @@ -30,6 +30,8 @@ export interface HasElementRef {
export type ThemePalette = 'primary' | 'accent' | 'warn' | undefined;

/** Mixin to augment a directive with a `color` property. */
export function mixinColor<T extends AbstractConstructor<HasElementRef>>(
base: T, defaultColor?: ThemePalette): CanColorCtor & T;
export function mixinColor<T extends Constructor<HasElementRef>>(
base: T, defaultColor?: ThemePalette): CanColorCtor & T {
return class extends base {
Expand Down
2 changes: 1 addition & 1 deletion src/material/core/common-behaviors/constructor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ export type Constructor<T> = new(...args: any[]) => T;
* This is a permissive type for abstract class constructors.
* @docs-private
*/
export type AbstractConstructor<T> = Function & { prototype: T };
export type AbstractConstructor<T = object> = abstract new (...args: any[]) => T;
19 changes: 8 additions & 11 deletions src/material/core/common-behaviors/disable-ripple.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {Constructor, AbstractConstructor} from './constructor';
import {AbstractConstructor, Constructor} from './constructor';

/** @docs-private */
export interface CanDisableRipple {
Expand All @@ -16,23 +16,20 @@ export interface CanDisableRipple {
}

/** @docs-private */
export type CanDisableRippleCtor = Constructor<CanDisableRipple>;
export type CanDisableRippleCtor = Constructor<CanDisableRipple> &
AbstractConstructor<CanDisableRipple>;

/** Mixin to augment a directive with a `disableRipple` property. */
export function mixinDisableRipple<T extends AbstractConstructor<{}>>(
base: T): CanDisableRippleCtor & T {
abstract class Mixin extends (base as unknown as Constructor<{}>) {
export function mixinDisableRipple<T extends AbstractConstructor<{}>>(base: T):
CanDisableRippleCtor & T;
export function mixinDisableRipple<T extends Constructor<{}>>(base: T): CanDisableRippleCtor & T {
return class extends base {
private _disableRipple: boolean = false;

/** Whether the ripple effect is disabled or not. */
get disableRipple() { return this._disableRipple; }
set disableRipple(value: any) { this._disableRipple = coerceBooleanProperty(value); }

constructor(...args: any[]) { super(...args); }
}

// Since we don't directly extend from `base` with it's original types, and we instruct
// TypeScript that `T` actually is instantiatable through `new`, the types don't overlap.
// This is a limitation in TS as abstract classes cannot be typed properly dynamically.
return Mixin as unknown as T & CanDisableRippleCtor;
};
}
5 changes: 3 additions & 2 deletions src/material/core/common-behaviors/disabled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import {coerceBooleanProperty} from '@angular/cdk/coercion';
import {Constructor} from './constructor';
import {AbstractConstructor, Constructor} from './constructor';

/** @docs-private */
export interface CanDisable {
Expand All @@ -16,9 +16,10 @@ export interface CanDisable {
}

/** @docs-private */
export type CanDisableCtor = Constructor<CanDisable>;
export type CanDisableCtor = Constructor<CanDisable> & AbstractConstructor<CanDisable>;

/** Mixin to augment a directive with a `disabled` property. */
export function mixinDisabled<T extends AbstractConstructor<{}>>(base: T): CanDisableCtor & T;
export function mixinDisabled<T extends Constructor<{}>>(base: T): CanDisableCtor & T {
return class extends base {
private _disabled: boolean = false;
Expand Down
11 changes: 7 additions & 4 deletions src/material/core/common-behaviors/error-state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import {FormControl, FormGroupDirective, NgControl, NgForm} from '@angular/forms';
import {Subject} from 'rxjs';
import {ErrorStateMatcher} from '../error/error-options';
import {Constructor} from './constructor';
import {AbstractConstructor, Constructor} from './constructor';


/** @docs-private */
Expand All @@ -21,7 +21,8 @@ export interface CanUpdateErrorState {
}

/** @docs-private */
export type CanUpdateErrorStateCtor = Constructor<CanUpdateErrorState>;
export type CanUpdateErrorStateCtor = Constructor<CanUpdateErrorState> &
AbstractConstructor<CanUpdateErrorState>;

/** @docs-private */
export interface HasErrorState {
Expand All @@ -35,8 +36,10 @@ export interface HasErrorState {
* Mixin to augment a directive with updateErrorState method.
* For component with `errorState` and need to update `errorState`.
*/
export function mixinErrorState<T extends Constructor<HasErrorState>>(base: T)
: CanUpdateErrorStateCtor & T {
export function mixinErrorState<T extends AbstractConstructor<HasErrorState>>(base: T):
CanUpdateErrorStateCtor & T;
export function mixinErrorState<T extends Constructor<HasErrorState>>(base: T):
CanUpdateErrorStateCtor & T {
return class extends base {
/** Whether the component is in an error state. */
errorState: boolean = false;
Expand Down
17 changes: 6 additions & 11 deletions src/material/core/common-behaviors/tabindex.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,14 @@ export interface HasTabIndex {
}

/** @docs-private */
export type HasTabIndexCtor = Constructor<HasTabIndex>;
export type HasTabIndexCtor = Constructor<HasTabIndex> & AbstractConstructor<HasTabIndex>;

/** Mixin to augment a directive with a `tabIndex` property. */
export function mixinTabIndex<T extends AbstractConstructor<CanDisable>>(
export function mixinTabIndex<T extends AbstractConstructor<CanDisable>>(base: T,
defaultTabIndex?: number): HasTabIndexCtor & T;
export function mixinTabIndex<T extends Constructor<CanDisable>>(
base: T, defaultTabIndex = 0): HasTabIndexCtor & T {
// Note: We cast `base` to `unknown` and then `Constructor`. It could be an abstract class,
// but given we `extend` it from another class, we can assume a constructor being accessible.
abstract class Mixin extends (base as unknown as Constructor<CanDisable>) {
return class extends base implements HasTabIndex {
private _tabIndex: number = defaultTabIndex;
defaultTabIndex = defaultTabIndex;

Expand All @@ -41,10 +41,5 @@ export function mixinTabIndex<T extends AbstractConstructor<CanDisable>>(
constructor(...args: any[]) {
super(...args);
}
}

// Since we don't directly extend from `base` with it's original types, and we instruct
// TypeScript that `T` actually is instantiatable through `new`, the types don't overlap.
// This is a limitation in TS as abstract classes cannot be typed properly dynamically.
return Mixin as unknown as T & Constructor<HasTabIndex>;
};
}
16 changes: 8 additions & 8 deletions tools/public_api_guard/material/core.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,19 +62,19 @@ export interface CanColor {
defaultColor: ThemePalette | undefined;
}

export declare type CanColorCtor = Constructor<CanColor>;
export declare type CanColorCtor = Constructor<CanColor> & AbstractConstructor<CanColor>;

export interface CanDisable {
disabled: boolean;
}

export declare type CanDisableCtor = Constructor<CanDisable>;
export declare type CanDisableCtor = Constructor<CanDisable> & AbstractConstructor<CanDisable>;

export interface CanDisableRipple {
disableRipple: boolean;
}

export declare type CanDisableRippleCtor = Constructor<CanDisableRipple>;
export declare type CanDisableRippleCtor = Constructor<CanDisableRipple> & AbstractConstructor<CanDisableRipple>;

export interface CanUpdateErrorState {
errorState: boolean;
Expand All @@ -83,7 +83,7 @@ export interface CanUpdateErrorState {
updateErrorState(): void;
}

export declare type CanUpdateErrorStateCtor = Constructor<CanUpdateErrorState>;
export declare type CanUpdateErrorStateCtor = Constructor<CanUpdateErrorState> & AbstractConstructor<CanUpdateErrorState>;

export declare abstract class DateAdapter<D> {
protected readonly _localeChanges: Subject<void>;
Expand Down Expand Up @@ -148,7 +148,7 @@ export interface HasTabIndex {
tabIndex: number;
}

export declare type HasTabIndexCtor = Constructor<HasTabIndex>;
export declare type HasTabIndexCtor = Constructor<HasTabIndex> & AbstractConstructor<HasTabIndex>;

export declare const MAT_DATE_FORMATS: InjectionToken<MatDateFormats>;

Expand Down Expand Up @@ -280,13 +280,13 @@ export declare class MatRippleModule {
static ɵmod: i0.ɵɵNgModuleDeclaration<MatRippleModule, [typeof i1.MatRipple], [typeof i2.MatCommonModule, typeof i3.PlatformModule], [typeof i1.MatRipple, typeof i2.MatCommonModule]>;
}

export declare function mixinColor<T extends Constructor<HasElementRef>>(base: T, defaultColor?: ThemePalette): CanColorCtor & T;
export declare function mixinColor<T extends AbstractConstructor<HasElementRef>>(base: T, defaultColor?: ThemePalette): CanColorCtor & T;

export declare function mixinDisabled<T extends Constructor<{}>>(base: T): CanDisableCtor & T;
export declare function mixinDisabled<T extends AbstractConstructor<{}>>(base: T): CanDisableCtor & T;

export declare function mixinDisableRipple<T extends AbstractConstructor<{}>>(base: T): CanDisableRippleCtor & T;

export declare function mixinErrorState<T extends Constructor<HasErrorState>>(base: T): CanUpdateErrorStateCtor & T;
export declare function mixinErrorState<T extends AbstractConstructor<HasErrorState>>(base: T): CanUpdateErrorStateCtor & T;

export declare function mixinInitialized<T extends Constructor<{}>>(base: T): HasInitializedCtor & T;

Expand Down

0 comments on commit 33104b6

Please sign in to comment.