Açıkça yazılmış tipli dizi, Http.Get'ten o tip olarak doldurulmuyor gibi görünüyor. Angular, Typescript, Javascript


Yani bu proje için iki sınıf tanımladım:

Müşteriİşi

export class CustomerJob {
    partNumber?: string;
    revision?: string;
    description?: string;
    dueDate?: Date;
    customer?: string;
    purchaseOrderNumber?: string;
    quantityDue?: number;
    quantityShipped?: number;
    salesOrderNumber?: number;
    salesOrderLineNumber?: number;
    salesOrderLineLotNumber?: number;
    itemID?: number;
    salesOrderCreateDate?: Date;
    salesOrderLineCreateDate?: Date;
    salesOrderLineLotCreateDate?: Date;
    progress?: number;
    shipVia?: string;
    status?: string;
    customDescription?: string;
    shippingLocation?: string;

    documents?: DocumentFile[];
    openQuantity?: number = 0;

}

BelgeDosyası

export class DocumentFile {
    id?: number;
    url?: string;
    fileName?: string;
    extension?: string;
    extensionWithoutPeriod?: string;
    isImageFile: boolean = false;


    setup () {
        console.warn('doing setup for document');
        // get name of file (filename.extension). need to remove all the \\ stuff basically
        let _stringArray = this.url?.split('\\');
        // the last one in this split is the filename and extension
        let _filenameWithExtension = _stringArray![_stringArray!.length - 1];

        // split this by period
        let _filenameSplit = _filenameWithExtension.split('.');

        // first one in array is the filename
        this.fileName = _filenameSplit![0];
        // second is extension
        this.extensionWithoutPeriod = _filenameSplit![1];
        this.extension = '.' + this.extensionWithoutPeriod;
    }
}

Benim şöyle görünen bir servisim var:

import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { firstValueFrom } from 'rxjs';
import { CustomerJob, DocumentFile } from '../dataModels/data-models';
import { LoginService } from '../services/login.service';

@Injectable({
  providedIn: 'root'
})
export class JobService {

  constructor(private http: HttpClient, private loginService: LoginService) { }


  jobs?: CustomerJob[] = [];


  async getCustomerJobs () {
    let headers = new HttpHeaders().set('APIKey', this.loginService.loginInformation!.apiKey);

    try {
      this.jobs = await firstValueFrom(this.http.get<CustomerJob[]>('https://XXXXX', { headers: headers }));

      // do some modifications to them
      this.jobs.forEach(function (j) {
        // quantity
        if (j.quantityDue != undefined && j.quantityShipped != undefined) {
          j.openQuantity = j.quantityDue - j.quantityShipped;
        }

        // document stuff
        if (j.documents != undefined) {
          j.documents.forEach(d => {
            // console.warn('setting up F');
            if (d == undefined) {
              console.warn('this document is undefined');
            }
            else {
              //d = Object.assign(d, j.documents[i]);

              console.warn('this document is defined: ' + d.id + ', ' + d.url);

              d.setup();

              console.warn(d.fileName);
            }   
          });


         
        }
        else {
          console.warn('this one DOES NOT have documents');
        }

      });

    }
    catch (error: any) {
      console.error('CATCH ERROR: ' + error.message);
    }

    return this.jobs;

  }
  

}

Bunu TryCatch üzerinden konsolda aldığım hata.

d.setup is not a function

Burada önemli olan şey, aslında hemen öncesindeki satırda bazı bilgileri doğru şekilde yazdırıyor olmasıdır:

console.warn('this document is defined: ' + d.id + ', ' + d.url);

Sonunda anladım ki sorun muhtemelen "d"nin aslında bir DocumentFile türü olmaması. Bunun nedenini çözemedim çünkü CustomerJob sınıfında dizi özellikle bir DocumentFile dizisi olarak türlendirilmiş. Yani bir noktada, tahminimce Http.Get üzerinden CustomerJobs dizisini oluştururken, özel olarak türlendirilmiş DocumentFile dizisini anonim nesneler dizisine veya başka bir şeye dönüştürüyor.

Bunun doğru olduğunu biliyorum çünkü kodu şöyle değiştirdiğimde sorunsuz çalışıyor:

j.documents.forEach(d => {
            // console.warn('setting up F');
            if (d == undefined) {
              console.warn('this document is undefined');
            }
            else {
              let doc: DocumentFile = new DocumentFile();
              Object.assign(doc, d);

              console.warn('this document is defined: ' + doc.id + ', ' + doc.url);

              doc.setup();

              console.warn(doc.fileName);
            }   
          });

Ben C# kullanmaktan geliyorum, bu yüzden JavaScript gibi gevşek türlü dillerle her zaman sorun yaşıyorum. Bu çok sinir bozucu. Yardımınız için şimdiden teşekkür ederim.

Cevap #1

Sorununuz, HttpClient sunucudan gelen sonuçları serileştirirken, aslında hangi biçimde olmasını istediğini bilme yolunun olmamasıdır. TypeScript arayüzleri ve tipleri tamamen derleme zamanı öğeleridir, C#’ta yansıma kullanabileceğinizin aksine. Geliştirici araçlarını açıp API çağrınızdan gelen sonuçlara bakarsanız, verilerinizin saf JSON olduğunu göreceksiniz. HttpClient da bunu görür.

Ağ sınırındaki TypeScript arayüzleri sadece belgelerdir, sunucudan gerçekten gelenle eşleşecek şekilde belgeleri yazmak size kalmıştır.

DocumentFile sınıfınızı bir arayüz olarak değiştirmenizi, kurulum kodunu normal bir fonksiyon tanımına taşımanızı ve sadece şöyle çağırmanızı tavsiye ederim:

setup(doc);

C#'tan gelen biri için sadece bir fonksiyon tanımının ortada duruyor olması garip gelebilir, ama size temin ederim ki bu tamamen normal ve bu tür bir durumu yönetmenin oldukça standart bir yoludur.