машинописное объединение в классе - PullRequest
1 голос
/ 09 мая 2020

я изучаю ioni c и angular. В этом приложении я использую следующий класс

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);
      })
    );
  }
}

updates.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>

Я получаю сообщение об ошибке из кода VS: Identifier 'userName' is not defined. 'ReactionObject | ObituaryObject' does not contain such a member Однако это по-прежнему отображает данные правильно, также IntelliSense показывает только два варианта: categoryId & obituaryId , которые являются общими для обоих классов. Замена ObituaryObject на any устраняет ошибку

Есть идеи, почему я получаю эту ошибку?

Спасибо

Ответы [ 2 ]

0 голосов
/ 09 мая 2020
public object: ReactionObject | ObituaryObject

это определяет, что object может быть любого из типов ReactionObject или ObituaryObject

 {{ feed.object.userName }} // issue here

Измените его на :

  {{ (feed.object as ReactionObject).userName }} // issue should be resolved.

или

  {{ (<ReactionObject>feed.object).userName }} // issue should be resolved.

Также добавьте импорт ReactionObject в `updates.component.ts

import { ReactionObject } from './model.ts'  // check the path for model.ts

Обновить :

В updates.components.ts добавлен геттер

get feedObjectUserName() { 
  return ( <RectionObject> feed.object).userName
}

и в updates.component.html изменен на

{{ feedObjectUserName }}

Надеюсь, это поможет!

0 голосов
/ 09 мая 2020

Я думаю, это потому, что в вашем классе Feed у вас есть поле object с двумя доступными типами, использующими Union Type . ObituaryObject не имеет поля userName.

Я бы предложил избегать UnionType в пользу родительского объекта, используя наследование TypeScript .

Также ваш код таким образом будет более понятным.

ПОЛНЫЙ РАБОЧИЙ КОД ЗДЕСЬ .

Модель / Просмотр / Компонент

Ваша модель станет такой:

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);
  }
}

Далее, при доступе к полю из представления, принудительно проверяйте указанный класс c, например это:

 {{ getReaction(obituaryObject.object).username }}

Имея метод, определенный следующим образом:

getReaction(object: GenObject) {
   if (object instanceof ReactionObject) {
     return object as ReactionObject;
   }
 }
...