Angular typing: Why won't Typescript treat a component subclass as assignable to its...

Discussão em 'Angular' iniciado por kshetline, Março 18, 2025.

  1. kshetline

    kshetline Guest

    I have two Angular components which share a lot of common appearance and behavior, so much of that commonality is in an abstract superclass. Here's the start of that superclass:

    @Directive({ standalone: true })
    export abstract class DigitSequenceEditorDirective<T> implements
    AfterViewInit, ControlValueAccessor, OnInit, OnDestroy, Validator {
    ...


    And this is how the two subclasses are declared:

    @Component({
    selector: 'tbw-angle-editor',
    animations: [BACKGROUND_ANIMATIONS],
    templateUrl: '../digit-sequence-editor/digit-sequence-editor.directive.html',
    styleUrls: ['../digit-sequence-editor/digit-sequence-editor.directive.scss'],
    providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => AngleEditorComponent), multi: true },
    { provide: NG_VALIDATORS, useExisting: forwardRef(() => AngleEditorComponent), multi: true }],
    imports: [NgStyle, NgClass],
    standalone: true
    })
    export class AngleEditorComponent extends DigitSequenceEditorDirective<number> implements OnInit {
    ...


    @Component({
    selector: 'tbw-time-editor',
    animations: [BACKGROUND_ANIMATIONS],
    templateUrl: '../digit-sequence-editor/digit-sequence-editor.directive.html',
    styleUrls: ['../digit-sequence-editor/digit-sequence-editor.directive.scss', './time-editor.component.scss'],
    providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TimeEditorComponent), multi: true },
    { provide: NG_VALIDATORS, useExisting: forwardRef(() => TimeEditorComponent), multi: true }],
    imports: [NgClass, NgStyle],
    standalone: true
    })
    export class TimeEditorComponent extends DigitSequenceEditorDirective<number> implements OnInit {
    ...


    (A lot of redundant boilerplate in the declarations, but no way to reduce that much that I know of.)

    I would think (but apparently I am wrong) I should be able to pass either AngleEditorComponent or TimeEditorComponent to a function with a generic type that extends DigitSequenceEditorDirective<any>, something I need to do to effectively consolidate a lot of common Karma/Jasmine test code. Part of that common code looks like this:

    type DigitSequenceSuperclass = DigitSequenceEditorDirective<any>;

    export class CommonTestEnvironment<T, U extends DigitSequenceSuperclass> {

    // ...


    export async function sharedBeforeEach<T, U extends DigitSequenceSuperclass>(qlass: Type<T>, innerClass: U,
    selector: string, initValue: string): Promise<CommonTestEnvironment<T, U>> {
    await TestBed.configureTestingModule({
    // ...


    Unless I just hack around the issue with @ts-ignore, this is the grief I get:

    [​IMG]

    So, DigitSequenceEditorDirective<T> is not a class derived from... itself?

    Can anyone explain what might be happening here, and offer a better work around than @ts-ignore?

    The unit testing is working fine, by the way, using the common code. I'd just prefer cleaner typing if I can manage it.

    Full source code here: https://github.com/kshetline/tubular_ng-widgets/tree/development

    Continue reading...

Compartilhe esta Página