angular - typescript-union i en klass
Jag lär mig Ionic & Angular. I den här appen använder jag nedanstående klass
model.ts
export class Feed {
constructor(
public type: string,
public object: ReactionObject | ObituaryObject
) {}
}
export class ReactionObject {
constructor(
public actionId: string,
public obituaryId: string,
public categoryId: string,
public timestamp: string,
public userName: string,
public userPhoto: string,
public deceasedName: string,
public thanked: string,
public community: CommunityObject,
public obituarySponsorId: string
) {}
}
export class ObituaryObject {
constructor(
public categoryId: string,
public deathDay: string,
public funeral: FuneralObject,
public name: string,
public obituaryId: number,
public photo: string
) {}
}
types.ts
export interface ApiData {
error: string;
session_id: string;
data: any;
message?: string;
}
export interface FeedData extends ApiData {
type: string;
object: ReactionData | SingleObituaryData;
}
export interface ReactionData extends ApiData {
actionId: string;
obituaryId: string;
categoryId: string;
timestamp: string;
userName: string;
userPhoto: string;
deceasedName: string;
thanked: string;
community: CommunityData;
obituarySponsorId: string;
}
export interface SingleObituaryData extends ApiData {
categoryId: string;
deathDay: string;
funeral: FuneralData;
name: string;
obituaryId: number;
photo: string;
}
feed.service.ts
export class FeedService {
private _feed = new BehaviorSubject<Feed[]>([]);
get feed() {
return this._feed.asObservable();
}
constructor(private authService: AuthService, private http: HttpClient) {}
getFeed(pageNumber: number) {
return this.authService.userToken.pipe(
take(1),
switchMap((token) => {
return this.http.get<FeedData>(
`${environment.apiURL}getFeed&token=${token}&page=${pageNumber}`
);
}),
map((resData) => {
resData = resData.data.items;
console.log(resData);
const feed = [];
for (const key in resData) {
if (resData.hasOwnProperty(key)) {
feed.push(
new Feed(
resData[key].type,
new ReactionObject(
resData[key].object.actionId,
resData[key].object.obituaryId,
resData[key].object.categoryId,
resData[key].object.timestamp,
resData[key].object.userName,
resData[key].object.userPhoto,
resData[key].object.deceasedName,
resData[key].object.thanked,
resData[key].object.community,
resData[key].object.obituarySponsorId,
)
)
);
}
}
return feed;
}),
tap((feed) => {
this._feed.next(feed);
})
);
}
}
uppdateringar.component.html
<p class="ion-text-center" *ngIf="!isLoading && loadedFeed.length <= 0">
No updates found
</p>
<ion-list *ngIf="isLoading" class="ion-no-padding">
<ion-item *ngFor="let i of Arr(num).fill(1)">
<ion-avatar slot="start">
<ion-skeleton-text animated></ion-skeleton-text>
</ion-avatar>
<ion-label>
<p>
<ion-skeleton-text animated style="width: 80%;"></ion-skeleton-text>
</p>
</ion-label>
</ion-item>
</ion-list>
<ion-list *ngIf="!isLoading && loadedFeed.length > 0" class="ion-no-padding">
<ion-item *ngFor="let feed of loadedFeed">
<ng-container
*ngIf="
feed.type === 'candle' ||
feed.type === 'flower' ||
feed.type === 'comment'
"
>
<ion-avatar slot="start">
<img src="../../../assets/img/{{ feed.type }}-icon.svg" />
</ion-avatar>
<ion-label>
{{ feed.object.userName }} // issue here
<ng-container *ngIf="feed.type === 'candle'">
lit a candle on
</ng-container>
<ng-container *ngIf="feed.type === 'flower'">
placed a flower on
</ng-container>
<ng-container *ngIf="feed.type === 'comment'">
wrote a message on
</ng-container>
</ion-label>
</ng-container>
</ion-item>
</ion-list>
Jag får ett fel från VS Code: Identifier 'userName' är inte definierad. 'ReactionObject | ObituaryObject' innehåller inte en sådan medlem Men detta visar fortfarande datan korrekt, och IntelliSense visar bara två alternativ: categoryId & obituaryId som är gemensamma för båda klasserna. Att ersätta ObituaryObject med any tar bort felet
Några idéer varför jag får det här felet?
Tack
Svar #1
Jag tror att det beror på att du i din Feed-klass har fältet object med två tillgängliga typer som använder Union Type. ObituaryObject har inte fältet userName.
Jag skulle föreslå att undvika UnionType till förmån för ett faderobjekt som använder TypeScript-arv.
Också kommer din kod på detta sätt att vara tydligare.
FULLA ARBETSKOD HÄR.
Modell/Vy/Komponent
Din modell kommer att bli som :
export class GenObject {
constructor(
public obituaryId: number,
public categoryId: string
) {
}
}
export class Feed {
constructor(
public type: string,
public object: GenObject
) {
}
}
export class ReactionObject extends GenObject {
constructor(
public actionId: string,
public userName: string,
public obituaryId: number,
public categoryId: string
) {
super(obituaryId, categoryId);
}
}
export class ObituaryObject extends GenObject {
constructor(
public deathDay: string,
public name: string,
public obituaryId: number,
public categoryId: string
) {
super(obituaryId, categoryId);
}
}
Nästa, när du kommer åt fältet från vyn, tvinga kontrollen till den specifika klassen på detta sätt:
{{ getReaction(obituaryObject.object).username }}
Att ha metoden definierad så här:
getReaction(object: GenObject) {
if (object instanceof ReactionObject) {
return object as ReactionObject;
}
}
Svar #2
public object: ReactionObject | ObituaryObject
detta definierar att object kan vara av typerna ReactionObject eller ObituaryObject
{{ feed.object.userName }} // issue here
Ändra det till:
{{ (feed.object as ReactionObject).userName }} // issue should be resolved.
eller
{{ (<ReactionObject>feed.object).userName }} // issue should be resolved.
Lägg också till importen av ReactionObject i `updates.component.ts
import { ReactionObject } from './model.ts' // check the path for model.ts
Uppdatering:
I updates.components.ts lade till en getter
get feedObjectUserName() {
return ( <RectionObject> feed.object).userName
}
och i updates.component.html, ändrades till
{{ feedObjectUserName }}
Hoppas det hjälper!
