typescript - Angular 4, '{xx, xx}' türünde 'XX' özelliği eksik


Ben bu tür bir tür betiklemeye yeniyim. İşte model sınıfım:

export class Project {
     constructor(
          public projectId: number,
          public description: string,
          public startDate: Date,
          public endDate: Date
     ) {}
     getDaysRemaining() {
          var result = this.endDate.valueOf() - Date.now().valueOf();
          result = Math.ceil(result / (1000 * 3600 * 24));
          return result < 0 ? 0 : result;
     }
}

Ve aşağıda, Angular eğitimi için başlatmam yer almaktadır:

 let PROJECTS: Project[] = [
     { projectId: 1, description: "Sample", startDate: new Date("2016-12-12"), endDate: new Date("2017-1-13") },
     { projectId: 2, description: "Sample 2", startDate: new Date("2016-12-12"), endDate: new Date("2017-1-13") }
];

Modelin şablonda şu şekilde kullanılması bekleniyor:

{{ project.getDaysRemaining() }}

Ama, şu hatayı alıyorum:

Türünde '{ projectId: number; description: string; startDate: Date; endDate: Date; }' özelliği 'getDaysRemaining' eksik.

TypeScript'te fonksiyonu neden başlatmam gerekiyor? Yoksa bir şeyi mi kaçırıyorum?

Cevap #1

Sorununuz, bir sınıfın nasıl örneklendiğiyle ilgilidir.

Bunun yerine:

 let PROJECTS: Project[] = [
     { projectId: 1, description: "Sample", startDate: new Date("2016-12-12"), endDate: new Date("2017-1-13") },
     { projectId: 2, description: "Sample 2", startDate: new Date("2016-12-12"), endDate: new Date("2017-1-13") }
];

yapmalısın:

 let PROJECTS: Project[] = [
     new Project(1, "Sample", new Date("2016-12-12"), new Date("2017-1-13") ),
     new Project(2, "Sample 2", new Date("2016-12-12"), new Date("2017-1-13")
];

Açıklama

Project, bir sınıftır. getDaysRemaining(), o sınıfın bir üyesidir. Bir sınıfın örneğini oluşturmak için new Project(...) kullanabilirsiniz.

{ projectId: 1, ... }, Project sınıfının bir örneği olmayan bir nesnedir. Bu nedenle tüm üyeler, köşeli parantezler arasına özellikler olarak tanımlanmıştır.

{ projectId: 1, ... } öğesinin Project örneği olup olmadığını basitçe { project1: 1, ... } instanceof Project yazarak kontrol edebilirsiniz - sonuç false olur.

ES6? TypeScript, sözdizimi açısından JavaScript dilindeki en son gelişmelerle birçok ortak noktaya sahiptir. ES6'da sınıfları, TypeScript'te yaptığınız gibi tanımlayabilirsiniz. Elbette türler ve değiştiriciler hariç, çünkü JavaScript statik tipli bir dil değil, dinamik tipli bir dildir.

class Project {

    constructor(projectId, description, startDate, endDate) {
        this.projectId = projectId;
        this.description = description;
        this.startDate = startDate;
        this.endDate = endDate;
    }

     getDaysRemaining() {
          var result = this.endDate.valueOf() - Date.now().valueOf();
          result = Math.ceil(result / (1000 * 3600 * 24));
          return result < 0 ? 0 : result;
     }
}

ES6'da new Project() yapabilirsiniz, bu da tüm argümanlar için undefined üretir, ancak TypeScript'te yapılandırıcı argümanları eksik olduğu için yapamazsınız ve bu durum derleme zamanında kontrol edilir, ve eğer TypeScript sözdizimini kontrol eden iyi bir IDE varsa, tasarım zamanında da kontrol edilir.

TypeScript'te bunu mümkün kılmanın bir yolu, isteğe bağlı argümanları şöyle tanımlamaktır (argümanın yanındaki soru işaretine bakın):

 constructor(
      public projectId?: number,
      public description?: string,
      public startDate?: Date,
      public endDate?: Date
 ) { }

Yaygın problem - bir kaynaktan, örneğin bir web servisinden bazı veriler elde etmek

Web hizmetinden Project verilerinizi aldığınız duruma rastlayabilirsiniz. Bu durumda veriler düz nesnelere { projectId: 1, ... } deserialize edilecektir. Bu verilerden Project örneklerini elde etmek otomatik olarak yapılamaz ve ek çalışma yapılması gerekir.

En basit yöntem, her özelliği bir taraftan diğerine fabrika yönteminde geçirmektir:

class Project implements IProject {
    ...
    static create(data: IProject) {
        return new Project(data.projectId, data.description, data.startDate, data.endDate);
    }
    ...
}

ve verileriniz için ek yazım yardımı sağlamak üzere bir arayüzü (any yerine) kullanabilir ve ayrıca bunu uygulayabilirsiniz (class Project implements IProject):

interface IProject {
    projectId: number;
    description: string;
    startDate: Date;
    endDate: Date;
}

Başka bir seçenek isteğe bağlı argümanlar kullanmaktır, ancak bu her durum için geçerli olmayabilir:

class Project implements IProject {
     ...
     constructor(
          public projectId?: number,
          public description?: string,
          public startDate?: Date,
          public endDate?: Date
     ) { }

     static create(data: IProject) {
          return Object.assign(new Project(), data);
     }
     ...
}

bu nedenle arayüz, yukarıda belirtildiği gibi uygulanacaksa isteğe bağlı argümanlara sahip olurdu (soru işaretini kontrol edin):

interface IProject {
    projectId?: number;
    description?: string;
    startDate?: Date;
    endDate?: Date;
}

Derleme ve arayüzler TypeScript JavaScript'e dönüştürüldüğünde, tüm arayüzler nihai koddan kaldırılacaktır. JavaScript'te 'interface' (arayüz) kavramı yoktur. Bu, ek tür bilgisi sağlamak amacıyla TypeScript'in bir yapısıdır.

SAĞLAM olmaya çalışın - S=Tek Sorumluluk İlkesi

Yukarıdaki kodda Project iki sorumluluğa sahiptir (bir değil). İlk olarak bazı Project verilerini tutmak. İkincisi kalan günleri hesaplamak - getDaysRemaining. Bu, bir sınıf için çok fazla olabilir.

Temiz bir çözüm, bunu ikiye ayırmak olabilir.

Verilerin temsil edilmesi için bir Project arayüzüne sahip olun:

interface IProject {
    projectId: number;
    description: string;
    startDate: Date;
    endDate: Date;
}

Ve getDaysRemaining() metodunu başka bir sınıfa taşıyın, şöyle:

class ProjectSchedulingService {
    getDaysRemaining(project: IProject) {
        var result = project.endDate.valueOf() - Date.now().valueOf();
        result = Math.ceil(result / (1000 * 3600 * 24));
        return result < 0 ? 0 : result;
    }
}

Bunun avantajı, verinin - IProject - ayrı olması ve ek işlevselliğin kendi işlerini yapan diğer sınıflarda yer alabilmesidir - örneğin - ProjectSchedulingService.

Başka bir avantaj, IProject'in ek sınıflar oluşturmadan düz nesnelerle çalışmaya yardımcı olabilmesidir. Verileri bir web servisinden alabilir, bunları bir arayüze dönüştürebilir ve tipli bir şekilde çalışabilirsiniz.

Başka bir avantaj, işin birden fazla sınıfa bölünebilmesidir - örneğin ProjectSchedulingService - böylece tüm verilerin ve ilgili işlerin bulunduğu büyük bir monolitik sınıf yerine tek tek birim test yapılabilmesidir.

Bir diğer avantaj, birden fazla sınıfa sahip olmanın sınıflar arasındaki bağımlılıkları daha kolay tanımlamaya yardımcı olması, böylece iş mantığını koruması ve bir sınıfın tüm bağımlılıklarını taklit edebilme ve ilgili sınıfın iş mantığını birim testi yapabilme yeteneğidir.

Angular'ı örnek alın, ihtiyaç duyulduğu şekilde enjekte edilebilecek birden fazla servis (sınıf) olabilir. Tek bir monolitik servis having, sadece bir kısmına ihtiyaç duyulan bir şeyi geçmek anlamına gelir. Bu da arayüz ayrımını bozar.

Bu ilk başta saçma gelebilir, çünkü kod çok küçük, ama zaman geçtikçe bu büyümeye devam edecek ve sonraki geliştiriciler kodu yeniden yapılandırmak yerine aynı monolitik şekilde geliştirmeye devam edebilir. Bir süre sonra, birçok tahmin artacak veya kodun bakım zorluğu nedeniyle bozulacaktır. Ayrıca siklomatik karmaşıklık daha kötü hale gelir ve birim testleri için kod kapsamı da düşer.

İlgili makaleler