I have a base class with multiple extensions looking like this:
export interface ProjectOnePagerDTO {
Widgets: IOnePagerWidget[];
Id: string;
}
export interface IOnePagerWidget extends GridsterItem {
Type: OnePagerWidgetType;
}
export interface OnePagerWidgetTypePicture extends IOnePagerWidget {
ProjectLogo: string;
}
export interface OnePagerWidgetTypeProjectDescription extends IOnePagerWidget {
Text: string;
}
Each extension, e.g. OnePagerWidgetTypePicture, has its own component. In the template I loop through Widgets property of ProjectOnePagerDTO and pass each widget to its component. The component for OnePagerWidgetTypePicture looks like this
export class OpwProjectPictureComponent {
@Input() widget: OnePagerWidgetTypePicture;
}
Now I am getting following error: Property 'ProjectLogo' is missing in type 'IOnePagerWidget' but required in type 'OnePagerWidgetTypePicture'
.
What am I missing? Do I have to change the @Input type and cast it right inside of the component?
Try using Generics so that it accepts multiple types.
@Component({
selector: 'app-child',
template: ``,
})
export class Child<T> {
@Input() widget!: T;
}
Try using a function that determines the type based on the properties unique to that type.
typeIt(widget: CompositeWidgetType) {
if ((widget as OnePagerWidgetTypePicture).ProjectLogo) {
return widget as OnePagerWidgetTypePicture;
} else if ((widget as OnePagerWidgetTypeProjectDescription).Type) {
return widget as OnePagerWidgetTypeProjectDescription;
} else {
return widget as IOnePagerWidget;
}
}
import { Component, Input } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
export class GridsterItem {}
export class OnePagerWidgetType {}
export interface ProjectOnePagerDTO {
Widgets: IOnePagerWidget[];
Id: string;
}
export interface IOnePagerWidget extends GridsterItem {
Type: OnePagerWidgetType;
}
export interface OnePagerWidgetTypePicture extends IOnePagerWidget {
ProjectLogo: string;
}
export interface OnePagerWidgetTypeProjectDescription extends IOnePagerWidget {
Text: string;
}
@Component({
selector: 'app-child',
template: ``,
})
export class Child<OnePagerWidgetTypePicture> {
@Input() widget!: OnePagerWidgetTypePicture;
}
export type CompositeWidgetType =
| IOnePagerWidget
| OnePagerWidgetTypePicture
| OnePagerWidgetTypeProjectDescription;
@Component({
selector: 'app-root',
imports: [Child],
template: `
@for (widget of Widgets;track $index) {
@let typedWidget = typeIt(widget);
<app-child [widget]="typedWidget"/>
}
`,
})
export class App {
Widgets!: Array<CompositeWidgetType>;
typeIt(widget: CompositeWidgetType) {
if ((widget as OnePagerWidgetTypePicture).ProjectLogo) {
return widget as OnePagerWidgetTypePicture;
} else if ((widget as OnePagerWidgetTypeProjectDescription).Type) {
return widget as OnePagerWidgetTypeProjectDescription;
} else {
return widget as IOnePagerWidget;
}
}
}
bootstrapApplication(App);
If the parent component contains either of the three values, then shouldn't the array specify the same?
Here we can specify a type
named CompositeWidgetType
and assign it to the array.
export type CompositeWidgetType = IOnePagerWidget | OnePagerWidgetTypePicture | OnePagerWidgetTypeProjectDescription;
export interface ProjectOnePagerDTO {
Widgets: Array<CompositeWidgetType>;
Id: string;
}
Now when you pass in to the child component, it will take the respective type, since the type can be any of the three types.