2017-05-12 14 views
2

この種のタイプのスクリプトは初めてです。ここに私のモデルクラスがある:以下タイプ '{xx、xx}'に角4、プロパティ 'XX'がありません

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; 
    } 
} 

とは、私の初期化され、角度のチュートリアルを参照:

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") } 
]; 

モデルがテンプレートで次のように使用されることが期待されます。

{{ project.getDaysRemaining() }} 

しかし、エラーが発生しています:

Property 'getDaysRemaining' is missing in type '{ projectId: number; description: string; startDate: Date; endDate: Date; }'.

なぜTypeScriptで関数を初期化する必要がありますか?または、私は何かを逃していますか?

+0

次に、テンプレートの関数の結果を直接表示する方法はありません –

答えて

7

あなたの問題は、クラスのインスタンス化の仕方に関係しています。

の代わりに:あなたがすべき

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") } 
]; 

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") 
]; 

説明

Projectは、クラスです。 getDaysRemaining()は、そのクラスのメンバーです。クラスのインスタンスを作成するには、new Project(...)を使用します。

{ projectId: 1, ... }は、クラスProjectのインスタンスではないオブジェクトです。したがって、すべてのメンバーはプロパティとして角括弧の間に定義されます。

{ projectId: 1, ... }Projectのインスタンスであるかどうかを確認するには、単に{ project1: 1, ... } instanceof Project - falseとなります。

ES6? TypeScriptには、JavaScript言語の最新の進歩と共通する多くの構文があります。 ES6でクラスを定義するには、TypeScriptの場合と同様の方法があります。もちろん、JavaScriptのような型と修飾子を除いては、静的型付き言語ではなく、動的型付き型です。

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で

あなたはすべての引数にundefinedを得new Project()を行うことができますが、活字体でコンストラクタの引数が不足していることができないので、この事実は、コンパイル時にチェックされ、活字体をチェックする良いIDEがある場合また、設計時にも使用できます。

これは活字体でそうのようなオプションの引数を定義することで可能にするために、1つのオプション(引数の近くに疑問符を参照してください):

共通の問題 - ウェブのように、ソースからいくつかのデータを取得しますサービス

WebサービスからProjectデータを取得すると、この問題が発生することがあります。その場合、データは単純なオブジェクト{ projectId: 1, ... }に逆シリアル化されます。そのデータからProjectのインスタンスを取得することは暗黙的に行うことはできず、追加の作業を行う必要があります。

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

と入力中に、あなたは追加のヘルプを提供するために、あなたのデータのために(代わりにanyの)インターフェースを使用することができ、そして:

最も単純には、ファクトリメソッドで一方から他方に各プロパティを渡していますまた、(class Project implements IProject)それを実装する:

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

別のオプションは、オプションの引数を使用することですが、これはすべてのケースに適用されない場合があります。

活字体はJavaScriptにtranspiledされている間、すべてのインタフェースがあろう

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

コンパイルとインターフェース:上記のように実装される場合

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); 
    } 
    ... 
} 

210は、このようにインタフェースは、オプションの引数を(疑問符をチェック)を有するであろう最終コードから削除されました。 JavaScriptには「インターフェース」という概念はありません。これは、追加の型情報を提供することを目的とするTypeScriptの構成要素です。

固体であることを試みる - 上記のコードProject

シングル責任原則 = S 2人の責任(しないもの)を有しています。 1つは、Projectのデータを保持することです。 2番目は残りの日 - getDaysRemainingを計算することです。これは、単一のクラスにとってはあまりにも多すぎるかもしれません。

クリーンな解決策は、これを2つに分割することです。

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

など別のクラスにgetDaysRemaining()を移動: - IProject - である。これは、データが優位性を持っている

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; 
    } 
} 

Projectのデータを表現するためのインタフェースを持っています独立した追加の機能を - ProjectSchedulingServiceのような独自の仕事をする他のクラスに配置することができます。

もう1つの利点は、IProjectが、追加のクラスをインスタンス化するのではなく、プレーンオブジェクトでの作業に役立つことです。 Webサービスからデータを取得し、インターフェースにキャストし、型付きの仕方で作業することができます。

もう1つの利点は、ProjectSchedulingServiceのように複数のクラスに分割することができ、データとそれに関連するすべてのビジネスを含む重いモノリシッククラスを持つ代わりに、個別に単体テストできることです。

複数のクラスを持つと、クラス間の依存関係をより簡単に定義でき、ビジネスセマンティクスが維持され、クラスのすべての依存関係を模擬してクラスのビジネスをテストできます。

exmpleにAngularを指定すると、必要に応じて複数のサービス(クラス)を注入できます。モノリシックサービスを1つ持つことは、その一部だけが必要なものを渡すことを意味します。したがって、インターフェース分離も破っています。

コードは非常に小さいので、最初はばかげているかもしれませんが、時間が経つにつれて、これは成長し続け、次の開発者はリファクタリングではなく同じモノリシックな方法で開発を続けているかもしれません。しばらくすると、コードを維持するのが難しいため、多くの見積もりが増えたり、壊れたりします。また、cyclomatic complexityが最悪になり、単体テストのコードカバレッジも増加します。

+0

ありがとうございます。それは2017年であり、この冗長な答えは依然として非常に有用です。 – Emaro

関連する問題