typescript - Angular HttpClient, beklediğim nesneleri tam olarak geri döndürmüyor
Diyelim ki var
class Foo {
bar: string;
public doSomething() {}
}
Servisimde, sunucudan bunların bir dizisini alıyorum:
this.http.get<Foo[]>(...)
Bu işe yarıyor, beklediğim tüm değerleri alıyorum. AMA aldığım nesnelerden birini alıp üzerinde doSomething() yöntemini çağırmaya çalıştığımda, foo (Türü Foo olan) nesnesinin doSomething() yöntemine sahip olmadığına dair bir hata alıyorum.
Görünüyor ki http.get JSON'i doğru bir şekilde çözümledi ve nesnelerimin tüm özelliklerini atadı, ancak onlar için uygun prototipleri ayarlamakla uğraşmadı, bu yüzden özünde sadece isim olarak Foo'lar, Foo'nun tüm yöntemlerinden yoksunlar.
Bu normal mi yoksa yanlış bir şey mi yapıyorum? Teşekkür ederim.
Cevap #1
Etkili bir şekilde. Sonuçta, sadece JSON çözümlemesi yapıyorsunuz ve JSON çözümlemesinin sonucu sadece normal JavaScript nesneleri, asla özel sınıflar değildir. this.http.get<Foo[]> derleyici için sadece bir ipucudur, fakat generic parametre gerçekten hiçbir şey yapmaz. Bir nesneyi başka bir nesneye dönüştürmez, aynı zamanda onlara tür vermez.
Bir tavsiye olarak, servislere yapılan çağrıların sonucunu tip dönüşümü yaparken veya localStorage, sessionStorage ve benzerlerinden nesne alırken asla sınıfları kullanmamalısınız. Bunun yerine, metot içermeyen arayüzleri kullanmalısınız.
Ancak, nesnelerinizin gerçekten Foo sınıfına ait olmasını ve doSomething metoduna sahip olmasını istiyorsanız, istediğinizi başarmak mümkündür:
this.http.get<Foo[]>(...).do(items => items.forEach(item => Object.setPrototypeOf(item, Foo.prototype)));
Bu, her nesneye doğru prototipi verecektir. Ancak, bunun bir performans maliyeti vardır, çünkü oluşturulmuş nesnelerin prototipini değiştirmek tarayıcı optimizasyonunu bozar, bu yüzden bunu kendi riskinizle yapın.
Başka bir seçenek de Foo'ya bir yapıcı (constructor) vermek olacaktır:
class Foo {
constructor(item: Foo) {
Object.assign(this, item);
}
bar: string;
public doSomething() {}
}
Şimdi :
this.http.get<Foo[]>(...).pipe(map(items => items.map(item => new Foo(item)))).subscribe(...);
