Angular 2 Typescript:是否可以将接口作为参数传递给函数?

Ole*_*ann 7 typescript angular

我有以下问题:我从 JSON API 中提取数据。我目前为每个数据模型(例如文章、用户等)提供一个服务,并为每个数据模型提供一个模型类。但这很疯狂,而且无法真正维护。所以我想重构,以便为每个数据模型和一个统一的DataAPIService.

问题是,该DataAPIService查询 API 中的函数不应返回 JSON,而是已查询类型的对象或对象集合。所以我需要一种方法将接口或类型传递到服务的查询方法中,然后初始化这种类型的新对象。

这可能吗?我说得通吗?这里有一些代码可以帮助理解我的意思并显示我当前的进度。

import { Injectable } from '@angular/core';

import { AuthHttp } from 'angular2-jwt';
import 'rxjs/add/operator/map';

import { Config } from '../config/env.config';

@Injectable()
export class DataAPIService {

  constructor(
    private authHttp: AuthHttp
  ) {}

  // This function will be called to retrieve data (for example from a Component). 
  // I want to pass in the object type or interface so that I only have one 
  // getIndex() function and not one for every data type.

  getIndex(page:number = 1, object_name:string, object_type) {
    return this.authHttp.get(Config.API_ENDPOINT + '/' + object_name + '?page=' + page)
      .map(res => res.json())
      .map(res => {
        return this.fromJson(res.data, object_type);
      });
  }

  // This function just checks which attributes are present in the object type 
  // and fills a new object of this type with the values from JSON.  
  // This is partly pseudo-code since I don't know how to solve this.

  fromJson(input_json: any, object_type) {
    // The next line is obviously not working. This is what I'm trying to figure out
    var object:object_type = new object_type();
    var json_attributes = input_json.attributes;
    for (var key in json_attributes) {
      if (object.hasOwnProperty(key)) {
        object[key] = json_attributes[key];
      }
    }
    object.id = input_json.id;
    return object;
  }

}
Run Code Online (Sandbox Code Playgroud)

Kwi*_*enP 5

您可以做的是使用泛型(如果您不知道这些是什么,我建议您使用谷歌搜索)。

@Injectable()
export class DataAPIService {

  constructor(
    private authHttp: AuthHttp
  ) {}

  // This function will be called to retrieve data (for example from a     Component). 
  // I want to pass in the object type or interface so that I only have one 
  // getIndex() function and not one for every data type.

  getIndex<T>(page:number = 1, object_name:string): Observable<T> {
    return this.authHttp.get(Config.API_ENDPOINT + '/' + object_name +     '?page=' + page)
      .map(res => res.json());
  }
Run Code Online (Sandbox Code Playgroud)

通过将 T 泛型添加到您的方法中,您可以将返回类型定义为类型为 T 的值的 Observable。 res.json() 将只创建一个对象,如果它返回给此方法的调用者,他将只看到类型为 T 的值的 observable。无需为接口编写这样一个特定的解析函数。


Ole*_*ann 1

这就是我解决整个问题的方法。对我来说很重要的是,生成的对象不是通用对象,而是 Post 类型的对象。我还想使用接口,并且希望对象的初始化很容易。

首先,我有一个所有数据模型都继承自的基类。

基础模型.model.ts

import * as _ from 'lodash';

export class BaseModel {

  public id: string;
  [key: string]: any;

  constructor(private data?: any) {
    // This basically does the initialization from a variable json object. 
    // I later on just pass the json data into the constructor.
    if (data) {
      this.id = data.id;
      _.extend(this, data.attributes);
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

现在从基本模型继承的实际模型:

成员模型.ts

// The actual model. It has an interface and extends the base class 
// (so that the main logic is just in one place - DRY)

import { BaseModel } from './base-model.model';

interface MemberInterface {
  email:string;
  name:string;
}

export class Member extends BaseModel implements MemberInterface {

  email:string;
  name:string;

  constructor(data?: any) {
    super(data);
  }

}
Run Code Online (Sandbox Code Playgroud)

让我们使用它吧。使用从 API 提取数据的服务

import { Injectable } from '@angular/core';
import { AuthHttp } from 'angular2-jwt';
import 'rxjs/add/operator/map';
import { Config } from '../config/env.config';

@Injectable()
export class MemberService {

  constructor(public authHttp: AuthHttp) {}

  // Calls the API and returns the result.
  // authHttp works very similar to http. Just with added JWT protection
  // check it out on GitHub: angular2-jwt
  getIndex(page:number = 1):any {
    let url = [Config.API_ENDPOINT, 'members', '?page='].join('/');
    return this.authHttp.get(url + page)
      .map(res => res.json())
      .map(res => {
        return res;
      });
  }

  // Simpler example when just getting one entry
  getOne(id: string):any {
    let url = [Config.API_ENDPOINT, 'members', id].join('/');
    return this.authHttp.get(url)
      .map(res => res.json())
      .map(res => {
        return res;
      });
  }


}
Run Code Online (Sandbox Code Playgroud)

最后让我们一起使用 Model 类和 Service

import { Component, OnInit } from '@angular/core';

import { MemberService } from '../shared/index';
import { Member } from '../shared/models/member.model';

@Component({
  moduleId: module.id,
  selector: 'app-member-list',
  templateUrl: 'member-list.component.html',
  styleUrls: ['member-list.component.css']
})
export class MemberListComponent implements OnInit {

  private members: Array<Member>;
  private member: Member;

  constructor(private memberService: MemberService) {
    this.members = [];
    this.member = new Member();
  }

  ngOnInit():any {
    // Pull the list on initialization
    this.getIndex(1);
  }

  // For the index
  getIndex(page:number = 1):Array<Member> {
    this.memberService.getIndex(page).subscribe(
      res => {
        this.members = [];
        for(let i = 0; i < res.data.length; i++) {
          let member = new Member(res.data[i]);
          this.members.push(member);
        }
      },
      err => console.log(err)
    );
  }

  // Simpler version with just one entry 
  getOne():any {
    this.memberService.getIndex(page).subscribe(
      res => {
        this.member = new Member(res.data.attributes);
      },
      err => console.log(err)
    );
  }

}
Run Code Online (Sandbox Code Playgroud)