Joel Joel - 1 month ago 13
TypeScript Question

Enforce type in typescript by using interfaces

I'm using something similar to this https://github.com/angular/angular/pull/11235 to render dynamic modals.

The directive has an input that takes the type a the Component that it will render:

@Directive({ selector: '[ngComponentOutlet]' })
export class NgComponentOutlet implements OnChanges {
@Input() ngComponentOutlet: Type<any>;
@Input() ngOutletInjector: Injector;
@Input() ngOutletProviders: Provider[];
@Input() ngOutletProjectableNodes: any[][];

@Output()
ngOutletCreated = new EventEmitter<ComponentRef<any>>(false);

constructor(
private _cmpFactoryResolver: ComponentFactoryResolver,
private _viewContainerRef: ViewContainerRef) { }

ngOnChanges(changes: SimpleChanges) {
if (changes.hasOwnProperty('ngComponentOutlet')) {
this._viewContainerRef.clear();

if (this.ngComponentOutlet) {
let injector = this.ngOutletInjector || this._viewContainerRef.parentInjector;

if (Array.isArray(this.ngOutletProviders) && this.ngOutletProviders.length > 0) {
injector = ReflectiveInjector.resolveAndCreate(this.ngOutletProviders, injector);
}

const cmpRef = this._viewContainerRef.createComponent(
this._cmpFactoryResolver.resolveComponentFactory(this.ngComponentOutlet),
this._viewContainerRef.length, injector, this.ngOutletProjectableNodes);

this.ngOutletCreated.emit(cmpRef);
}
}
}
}


I would like to enforce an interface on the components that can be used like this, so that I know that all Components dynamically rendered has a certain function, for example:

export interface ModalContent {
close(): void;
}


All the components that are going to be dynamic modals implements this:

@Component({
...
})
export class MyCustomModalComponent implements ModalContent {
close() {
...
}
}


And then I put it all together

@Component({
template: `<div [ngComponentOutlet]="component"></div>`,
})
export class AppComponent {
private component: ModalContent;

showModal() {
this.component = MyCustomModalComponent; <-- I get the error here
}
}


My problem is that I get the following error in AppComponent:

Type 'typeof MyCustomModalComponent' is not assignable to type 'ModalContent'.
Property 'close' is missing in type 'typeof MyCustomModalComponent'.


I guess it has to do with how I handle the types along the way, but I'm now sure what the problem is?

EDIT I added the entire Directive for reference

Answer

This code says component is of type ModalContent which means it can hold an instance of ModalContent.

private component: ModalContent;

This code assigns an instance of type Type, not of type ModalContent

this.component = MyCustomModalComponent;

This code would comply to the type annotations

this.component = new MyCustomModalComponent();

but you are not supposed to instantiate components yourself but instead let Angulars DI do it for you.

Not sure what you actually try to accomplish though.

update

If you actually want to assign a reference to the type, this should work:

private component: Type<ModalContent>