【问题标题】:typescript: need to provide class _methods_ for class instantiation?打字稿:需要为类实例化提供类_methods_?
【发布时间】:2018-07-12 02:36:28
【问题描述】:

我已经在我的打字稿项目中声明了一个类 Month。它有 6 个属性和 7 个成员方法,其中 4 个是私有的。

当尝试通过以下代码实例化 Month 的实例时,我收到一条错误消息,指出我没有提供方法作为参数的参数。 this.hasAdditionalCategories 是类方法。为什么我需要提供它?我的理解是我只需要提供属性来实例化,然后实例将继承类定义中的方法。

这看起来有道理吗?干杯

错误信息是

[ts] 类型参数 '{ date: Date;评论:空;预期现金流:数字;对冲比率:数字; expectedCashFlowHedge:...' 不可分配给“月份”类型的参数。 类型“{ date: Date;”中缺少属性“hasAdditionalCategories”评论:空;预期现金流:数字;对冲比率:数字;预期现金流对冲:...'。

const M: Month = new Month({
  date: new Date(),
  comment: null,
  expectedCashFlow: 0,
  hedgeRatio: 0,
  expectedCashFlowHedge: 0,
  categories: []
})

export class Month {
  date: Date;
  expectedCashFlow: number;
  hedgeRatio: number;
  expectedCashFlowHedge: number;
  categories: Category[] = [];
  comment: string;
  constructor(x: Month) {
    if (x) {
      this.date = x.date;
      this.expectedCashFlow = x.expectedCashFlow;
      this.hedgeRatio = x.hedgeRatio;
      this.expectedCashFlowHedge = x.expectedCashFlowHedge;
      x.categories.forEach(
        res => this.categories.push(
          new Category(res)
        )
      );
      this.comment = x.comment;
    }
  }

  get hasAdditionalCategories(): boolean {
    return this.categories.length > 1;
  }

  get hasComment(): boolean {
    if (!this.comment) {
      return false;
    } else {
      return this.comment.length > 0;
    }
  }

  reset(setting: IExposureSetting): void {
    this.resetCashFlows();
    this.resetHedgeRatio(setting);
    this.resetComment();
    this.resetCategories(setting);
  }

  private resetComment(): void {
    this.comment = null;
  }

  private resetCategories(setting: IExposureSetting): void {
    this.categories = [];
    const cat: Category = new Category({
      category: setting.assumedOriginOfExposure,
      hedgeRatio: setting.defaultHedgeRatio,
      expectedCashFlow: 0,
      expectedCashFlowHedge: 0
    });
    this.categories.push(cat);
  }
  private resetCashFlows(): void {
    this.expectedCashFlow = 0;
    this.expectedCashFlowHedge = 0;
  }
  private resetHedgeRatio(setting: IExposureSetting): void {
    this.hedgeRatio = setting.defaultHedgeRatio;
  }
}

【问题讨论】:

  • 不要试图伪造具有对象初始化器的类。只需使用对象并继续前进。你的方法意味着多年的痛苦和磨难。
  • Month 的构造函数采用了已经是Month 的东西?为什么?你为什么要尝试用普通值覆盖访问器?
  • ctor 中的 Month 参数在那里,因为我使用它来为它提供订阅中的元素。为了让我可以使用类方法。只是用 Observable 注释 observable 并没有让我得到类中定义的方法。实际上,如果在深度嵌套的“类类”中有几个的话,月份类就开始了……@aluan:对不起,我不明白这个的意思,我对这个还是很陌生
  • @baouss 我的意思就是这样。由于您是新手,因此不要对它是什么做出假设。特别是,避免尝试将 TypeScript 视为您已经知道的其他语言。提示:JavaScript 中的类与其他主流语言中的类完全不同。您不能使用相同的模式。
  • 感谢您回到这个话题。但我如何理解“伪装”?

标签: class typescript methods properties arguments


【解决方案1】:

由于构造函数将类的实例作为参数,因此无法构造(无论如何都不能强制转换为any)。

有几种解决方案,具体取决于您想要的安全程度以及您想要编写的垃圾:

匿名接口方法

您可以在构造函数声明中内联定义参数的结构:

constructor(x: {date: Date;
    expectedCashFlow: number;
    hedgeRatio: number;
    expectedCashFlowHedge: number;
    categories: Category[];
    comment: string;}) { ... }

Partial<T>

Partial<T> 是一个与T 结构相同但所有属性都标记为可选的类型。这种方法的缺点是您无法控制需要哪些参数,并且由于它具有T 相同的结构,您甚至可以指定一些函数。优点是您不必再次指定名称和类型,如果您添加更多字段,它们将自动出现在构造函数参数中

constructor(x: Partial<Month>) { ... }
new Month({
    comment: "", // we can specify public any field
    reset() { }  // But also methods which is not ideal
})

Pick&lt;T, K extends keyof T&gt;

Pick 允许我们使用K 定义的属性名称定义一个类型(它只能包含作为T 的键的字符串)以及与T 中的键具有相同的类型

constructor(x: Pick<Month, "categories" | "date" | "hedgeRatio" | "expectedCashFlow" | "expectedCashFlowHedge" | "comment">) { ... }

优点是你可以控制在构造函数中暴露哪些属性,所有属性都是必需的,如果一个属性被删除或重命名,编译器会抛出该属性不再属于@987654333的错误@

new Month({
    // we can specify all fields in the Pick
    comment: "", 
    date: new Date(),
    categories: [],
    expectedCashFlow: 0,
    hedgeRatio: 0,
    expectedCashFlowHedge: 0 
})

匿名接口方式并使用arg作为字段

最后的解决方案是更改类的结构并将所有属性保存在一个单独的状态字段中,该字段是构造函数的 arg 并在所有方法中使用它:

constructor(public state: {date: Date;
    expectedCashFlow: number;
    hedgeRatio: number;
    expectedCashFlowHedge: number;
    categories: Category[];
    comment: string;}) { ... }

【讨论】:

  • 非常感谢您非常详细的回答并提供了如此多的背景信息!这真的很有帮助。使用(匿名)界面有效。
  • @baouss,我没看到,没关系,是我的想法 :)
【解决方案2】:

您误解了类型的工作原理。

Month 表示看起来完全类似于Month 的东西,包括哪些方法和其他所有内容。就类型系统而言,您的声明意味着 ctor 可以在其参数上调用任何 Month 方法。

顺便说一句,这使您的类无法构造。

相反,如果您想采用这种方法,您可以将字段移动到基类或接口并让构造函数采用它。

【讨论】:

  • 谢谢,我回家试试这个。您对接口的建议是……我意识到我必须加深对类和接口的理解
  • 是的,效果很好。 I. 现在使用类实现的接口。现在使用 IMonth 类型的参数。事后看来,这个错误是非常合乎逻辑的。感谢您的帮助。
猜你喜欢
  • 2015-05-01
  • 2018-08-14
  • 1970-01-01
  • 1970-01-01
  • 2022-08-18
  • 1970-01-01
  • 2021-12-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多