web-dev-qa-db-ja.com

Angular2はJSON結果をインターフェイスにキャストします

Angular2とTypeScriptを使用して、webApiからJSONを返しました。これを特定のタイプの配列に入れる必要があります。 jsonを必要なインターフェイスにキャストする方法がわかりません。

私のタイプはこのインターフェイスです:

export interface Country {
    Id: number;
    Name: string;
}

私のモックはこの配列を返します:

export var COUNTRIES: Country[] = [
    { "Id": 11, "Name": "US" },
    { "Id": 12, "Name": "England" },
    { "Id": 13, "Name": "Japan" }
];

ここに私のコードがあります:country.service.ts

@Injectable()
export class CountryService {
    private _http = null;

    constructor(http: Http) {
        this._http = http;
    }

    getCountries() {
        return Promise.resolve(COUNTRIES);
    }
}

次に、これを呼び出します:

export class CountryPickerComponent {
    public countries: Country[];

    constructor(private _countryService: CountryService) { }


    getCountries() {
        this._countryService.getCountries().then(data => this.setData(data));
    }

    setData(data) {
        //this.countries = data;
        this.countries = JSON.parse(data);
        var q = 1;
    }

    ngOnInit() {
        this.getCountries();
    }
}  

ご覧のとおり、Countryインターフェイスの配列であるcountrysというクラス変数があります。これは期待どおりに機能します。 (私はそのsetDataメソッドが必要ないことを知っています-それはデバッグ用です)

次に、このjsonを返すwepApi呼び出しにサービスを変更しました。

"[{"name":"England","id":1},{"name":"France","id":2}]"

サービスのgetCountriesメソッドを次のように変更しました。

getCountries() {
    return new Promise(resolve=>
        this._http.get('http://localhost:63651/Api/membercountry')
            .subscribe(data => resolve(data.json()))
    );
}

JSON.parseを使用して、これをarrayに変換し、angular2で使用できるようにします。できます。データを含む配列を作成します。しかし、Countryインターフェースを実装する配列ではありません。

JSONのフィールド名はすべて小文字ですが、インターフェイスプロパティは大文字で始まり、インターフェイスにコーディングされていることに注意してください。その結果、実際のjsonを取得したときに機能しません。これをインターフェイスに「キャスト」する方法はありますか?エラーをスローし、何かが間違っていることを私に知らせる必要がありますか?

以下に示すように、多くの例ではgetでmapを使用しています。

  getCountries() {
        var retVal;

        return new Promise(resolve=>
            this._http.get('http://localhost:63651/Api/membercountry')
                .map(ref => ref.json())
                .subscribe(data => resolve(data.json()))
        );
    }

これに関するドキュメントが見つかりません。試してみても、データは取得できませんが、エラーはありません。コンパイルエラーもランタイムエラーもありません。

25
Don Chambers

JSON.parseによって作成されたオブジェクトで、期待しているインターフェースに対して型アサーションを行うことができます。

 this.http.get('http://localhost:4200/').subscribe((value: Response) => {
    let hero = <ServerInfo>value.json();
  });

ただし、2つの理由でサーバーから不良オブジェクトが送信された場合、エラーは発生しません。

コンパイル時には、トランスパイラーはサーバーが送信するものを知りません。

すべてがjavascriptにコンパイルされるため、実行時にすべての型情報が消去されます。

15
toskv

Viktor Savkinには タイプのランタイムチェックを行うライブラリ がありますが、TypeScriptはインターフェイスのランタイム情報をエクスポートしないため、インターフェイスでは機能しません。これについての議論があります here

次の2つの解決策があります。

  • APIからのデータが正しい形状であることがわかっていて、この形状に関するIDE /コンパイラ情報を提供するだけの場合、toskvの答えに従ってキャストできます。
  • APIが不明で、データの形状が正しくない場合にアプリにスローさせる場合は、独自のチェックを実装する必要があります。これは少しオーバーヘッドですが、より大きなアプリにとっては価値があります。

一般に、TypeScriptの型は、コンパイラが厳密な型システム以上のものを示唆しているように見えます。結局、型付けされていない言語にコンパイルする必要があります。

5