Angular 4,Property' XX'类型' {xx,xx}'

时间:2017-05-12 05:26:12

标签: angular typescript

我是这种类型脚本的新手。这是我的模型类:

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

以下是我的初始化,参考Angular教程:

 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() }}

但是,我收到了错误:

  

财产&#39; getDaysRemaining&#39;缺少类型&#39; {projectId:number;   描述:字符串; startDate:日期; endDate:日期; }&#39;

为什么我必须在TypeScript中初始化函数?或者,我错过了什么?

1 个答案:

答案 0 :(得分:12)

您的问题与实例化类的方式有关。

而不是:

 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中,您可以执行new Project(),为所有参数产生undefined,但在TypeScript中不能,因为缺少构造函数参数,并且在编译时检查此事实,如果有好的话IDE检查TypeScript语法,然后也在设计时检查。

在TypeScript中允许这样做的一个选项是定义像这样的可选参数(参见参数附近的问号):

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

常见问题 - 从来源获取一些数据,例如网络服务

当您从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;
}

另一种选择是使用可选参数,但这可能不适用于所有情况:

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

因此,如果要像上面那样实现,接口将具有可选参数(检查问号):

interface IProject {
    projectId?: number;
    description?: string;
    startDate?: Date;
    endDate?: Date;
}
将TypeScript转换为JavaScript时,

编译和接口将从最终代码中删除所有接口。没有&#34;界面&#34; JavaScript中的概念。这是TypeScript的构造,其目的是提供其他类型信息。

尝试坚固 - S =单一责任原则

在上面的代码Project中有两个职责(不是一个)。第一是保留一些Project数据。第二是计算剩余天数 - getDaysRemaining。对于单个班级来说,这可能太多了。

一个干净的解决方案可能是将其分成两部分。

有一个界面来表示Project

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

getDaysRemaining()移到另一个类,如:

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

这样做的好处是数据 - IProject - 是独立的,其他功能可以放在其他自己工作的类中 - 例如 - ProjectSchedulingService

另一个优点是IProject可以帮助处理普通对象,而不是实例化其他类。您可以从Web服务获取数据,将其转换为接口并以键入的方式工作。

另一个优点是业务可以分为多个类 - 例如ProjectSchedulingService - 因此可以单独进行单元测试,而不是拥有数据及其中所有相关业务的繁重单片类。

另一个优点是拥有多个类有助于更轻松地定义类之间的依赖关系,从而保持业务语义,并能够模拟类和单元的所有依赖关系来测试类的业务。

以Angular为例,您可以根据需要注入多个服务(类)。拥有一个单一的服务意味着传递只需要其中一部分的东西。因此也打破了界面隔离

这可能听起来很愚蠢,因为代码非常小,但随着时间的推移,这将继续增长,而下一代开发人员可能仍然以相同的整体方式继续开发而不是重构。经过一段时间后,由于维护代码的难度,许多估计值会增加或被破坏。同样cyclomatic complexity变得最差,也是单元测试的代码覆盖率。