Skip to content

fix(material/core): update mixin functions to avoid unknown cast #22577

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 3, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
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
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