In my Angular component I have an Input
that will be provided 1 of 2 types.
@Input() profile: UserProfileDetails | BusinessProfileDetails;
The profile template is simple and I'd like to use only the single template so I am not duplicating code. But because the types differ in properties I am receiving a template error.
export interface UserProfileDetails {
createdOn: Date;
id: string;
name: string;
}
export interface BusinessProfileDetails {
businessId: string;
businessLocation: string;
createdOn: Date;
id: string;
name: string;
}
and the code in my template:
<div>
<h1>{{profile.name}}</h1>
<div>{{profile.createdOn}}</div>
<div>{{profile.id}}</div>
<div *ngIf="profile?.businessId">{{profile.businessId}}</div>
<div *ngIf="profile?.businessLocation">{{profile.businessLocation}}</div>
</div>
I believe I understand why I am receiving the error, but I'm unsure how to resolve the issue while still using the or
condition @Input() profile: UserProfileDetails | BusinessProfileDetails;
CodePudding user response:
It's not really an or
although that's how you'd describe it; unintuitively it's called a union
type in TypeScript
Basically you can only reference properties that are common to both interfaces with |
Try an intersection type with &
instead
CodePudding user response:
You can set up a workaround using a function that check attribut on profile
using in
operator. Not the best solution but you'll be able to keep the interfaces union as you wished :
Component
getValue(
attribut: string,
obj: UserProfileDetails | BusinessProfileDetails
): any {
if (attribut in obj) {
return obj[attribut];
}
}
Template
<div>
<h1>{{ profile.name }}</h1>
<div>{{ profile.createdOn }}</div>
<div>{{ profile.id }}</div>
<div>{{ getValue('businessId', profile) }}</div> <!-- can be improved using a check method combined with ngIf -->
<div>{{ getValue('businessLocation', profile) }}</div>
</div>
CodePudding user response:
The issue you are facing is that angular's Template type checking seems enabled.
With the related settings enabled, the types of the objects used within the view are validated. If by any chance the object would not have one of the properties, these validations would cause the error you are facing.
Specifically in your case because the interface UserProfileDetails
does not have some of the properties used in the view, angular is considering the use of businessId
or businessLocation
an error.
there are some options to fix it:
- disable Template type checking (I would not recommend that)
- use a generic type for the
profile
variable (I would also not prefer this one) - use a pipe to cast the type of the object within the view. (my preference)
<div *ngIf="(profile | castProfileType)?.businessId">{{profile.businessId}}</div>
<div *ngIf="(profile | castProfileType)?.businessLocation">{{profile.businessLocation}}</div>
@Pipe({
name: 'castProfileType',
})
export class CastProfileTypePipe implements PipeTransform {
transform(value: profileObject) {
return Object.keys(value).includes('businessId') ? <BusinessProfileDetails>value : <UserProfileDetails>value
}
}
CodePudding user response:
You can also try with:
<div *ngIf="profile.hasOwnProperty('businessId')">{{profile.businessId}}</div>
<div *ngIf="profile.hasOwnProperty('businessLocation')">{{profile.businessLocation}}</div>
CodePudding user response:
go to tsconfig
file and change strict mode (line 8 if I remember correctly) to false