类中的打字稿联合

时间:2020-05-09 13:02:20

标签: angular typescript ionic-framework

我正在学习离子和角质。在此应用中,我正在使用以下课程

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 :(得分:0)

我认为这是因为在您的 Feed 类中,您有一个字段 object ,其中包含两个使用Union Type的可用提示。 ObituaryObject 没有字段userName。

我建议避免使用TypeScript inheritance使用UnionType来支持父对象。

通过这种方式的代码也将更加清晰。

完整工作代码HERE

Model / View / Component

您的模型将变为:

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

接下来,当从视图访问该字段时,将检查强制为这样的特定类:

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

具有如下定义的方法:

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

答案 1 :(得分:0)

public object: ReactionObject | ObituaryObject

这定义了object可以是ReactionObjectObituaryObject类型的

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

将其更改为:

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

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

还要在{updates.component.ts

中添加ReactionObject的导入
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 }}

希望有帮助!