Typescript 类型脚本、字段初始值设定项和派生类

Typescript 类型脚本、字段初始值设定项和派生类,typescript,Typescript,我正在用Typescript创建一个父类和子类。每个字段定义了一些字段属性。我试图保持代码干净,使用构造函数的Partial方法。但我不知道如何在超级调用中将父对象的属性传递给父对象,并在Object.assign中仅使用子对象的唯一道具初始化子对象的道具-如果这是正确的范例的话。以下是我所拥有的: export class Parent { name: string = '' durationInSec: number = 0.0 optionalField?: string;

我正在用Typescript创建一个父类和子类。每个字段定义了一些字段属性。我试图保持代码干净,使用构造函数的Partial方法。但我不知道如何在超级调用中将父对象的属性传递给父对象,并在Object.assign中仅使用子对象的唯一道具初始化子对象的道具-如果这是正确的范例的话。以下是我所拥有的:

export class Parent {
  name: string = ''
  durationInSec: number = 0.0
  optionalField?: string;
  constructor(init: Partial<Parent>) {
    Object.assign(this, init)
  }
}

export enum Types { A, B, C }

export class ChildA extends Parent {
  kind = Types.A
  childRequired1: string = '' // ??? have to set defaults for all props with this technique
  childOption1?: string
  constructor(init: Partial<ChildA>) {
    super(init) // ??? wrong, passes too many things to super
    Object.assign(this, init) // this would be fine alone, but tsc says need to call super()
  }
}

// similar for ChildB, ChildC etc.
let obj1 = new ChildA({name: 'foo', childRequired1: 'bar'})
这在Typescript中是一个好的范例吗?有更好的方法吗?

问题是init是部分的,所以如果您不为childRequired1声明默认值,那么就没有什么可以阻止某人执行新的ChildA{}事实上,Parent.durationnsec实际上不是Parent的可选选项,但您依赖于默认值

问题的第二部分是,似乎使用Object.assignthis。。。在构造函数中,似乎不满足初始化构造函数中所有必需参数的要求。关于这件事,似乎有一个很好的解释

在我看来,你有两个选择:

在所有必需的类型中设置默认值,以确保它们始终具有值,并且仍然可以使用Partial

要详细得多:


我很害怕。重复太多了!每个字段名必须键入三次。也许使用构造函数参数属性更好?这似乎不太酷,因为您没有更容易地扩展好的命名参数,顺序不重要,等等。。还有,在每个派生类的超级调用和构造函数参数列表中,您必须重复所有基类的成员,所以这甚至不是更好。您还可以使用childRequired1!之类的工具来完成一些骇客操作:字符串,使TypeScript认为它总是有一个值。然而,如果你忘记提供一个值,你会失去任何形式的理智检查???必须使用此技术为所有道具设置默认值。。。替代方案是什么?如果你需要道具,你需要在某个地方设置默认值,对吗?还是我遗漏了什么?另外,为什么不在子类中调用super{},然后执行Object.assignthis,init之后呢?我希望父类的一些字段是必需的,一些是可选的,并且是相同的w/child。使用这种方法,我似乎必须为必填字段设置默认值,因为部分字段是必需的,所以它们实际上不是必需的。
export class Parent {
  name: string;
  durationInSec: number;
  optionalField?: string;
  constructor(init: Parent) {
      this.name = init.name;
      this.durationInSec = init.durationInSec;
      this.optionalField = init.optionalField;
  }
}

export enum Types { A, B, C }

export class ChildA extends Parent {
  kind: Types;
  childRequired1: string;
  childOption1?: string;
  constructor(init: ChildA) {
    super(init as Parent) // Downcasted, it should be ok.
    this.kind = init.kind;
    this.childRequired1 = init.childRequired1;
    this.childOption1 = init.childOption1;
  }
}

let obj1 = new ChildA({
    name: 'foo',
    childRequired1: 'bar',
    durationInSec: 1,
    kind: Types.A
});