Typescript:通过传递命名参数的构造函数创建类?

Mar*_*tin 19 named-parameters typescript

我有一个类,我用3个参数定义了构造函数,这些参数都是可选的.我希望能够传入命名参数,所以我不需要传入undefined.

constructor(year?: number,
            month?: number,
            date?: number)
Run Code Online (Sandbox Code Playgroud)

我希望像这样创建一个类的intance

  const recurrenceRule = new MyNewClass(month: 6)
Run Code Online (Sandbox Code Playgroud)

但它没有用,我试过了

  const recurrenceRule = new MyNewClass(month = 6)
Run Code Online (Sandbox Code Playgroud)

那不起作用.

我得到它的唯一方法是

  const recurrenceRule = new MyNewClass(undefined, 4)
Run Code Online (Sandbox Code Playgroud)

要么

  const recurrenceRule = new MyNewClass(, 4)
Run Code Online (Sandbox Code Playgroud)

但它似乎很混乱,我希望传递命名参数,因为它们都是可选的我应该能够传入1 - 对吗?

SVS*_*idt 30

您可以使用ES6中引入的Object destructuring来实现所需的行为:reference.TypeScript能够转换此功能,以便与ES5一起使用以定位旧版浏览器.但是,从ES6开始,这也是完全有效的JavaScript.

基本上,它看起来像这样:constructor({ year, month, day})并且例如被调用为new Bar({ year: 2017 }).然后,您可以year在构造函数中作为变量进行访问,例如用于分配this.year = year.

比这更有趣的是使用默认值,例如

constructor({ year = new Date().getFullYear(), 
              month = new Date().getMonth(), 
              day = new Date().getDay()
            } = {})
Run Code Online (Sandbox Code Playgroud)

它允许分别使用0,1,2或3个参数调用构造函数(请参阅下面的代码段).

= {}当你创建一个没有任何参数的新实例时,有点神秘.首先,{}用作参数对象的默认值.然后,由于year缺少,将添加该值的默认值,然后分别为月份和日期.

对于TypeScript的使用,您当然可以添加其他类型,

constructor({ year = new Date().getFullYear(),
              month = new Date().getMonth(),
              day = new Date().getDay()
}: { year?: number, month?: number, day?: number } = {}) { 
    ...                
}
Run Code Online (Sandbox Code Playgroud)

虽然这看起来真的很神秘.

class Bar {
  constructor({ year, month, day }) {
    this.year = year;
    this.month = month;
    this.day = day;
  }
  
  log () {
    console.log(`year: ${this.year}, month: ${this.month}, day: ${this.day}`);
  }
}

new Bar({ day: 2017 }).log();

class Foo {
  constructor({ year = new Date().getFullYear(), 
                month = new Date().getMonth(), 
                day = new Date().getDay()
              } = {}) {
    this.year = year;
    this.month = month;
    this.day = day;
  }
  
  log () {
    console.log(`year: ${this.year}, month: ${this.month}, day: ${this.day}`);
  }
}

console.log('with default value:');
new Foo().log();
new Foo({ day: 2 }).log();
new Foo({ day: 2, month: 8 }).log();
new Foo({ year: 2015 }).log();
Run Code Online (Sandbox Code Playgroud)


elm*_*elm 11

class Bar {
  constructor({a, b}: {a?: number, b?: number}) {}
}

new Bar({b: 1})
Run Code Online (Sandbox Code Playgroud)

有关更多信息,请参阅ES6 Object Destructuring with functions

  • @TBG 如果您希望它们显示为类的属性,您仍然必须在构造函数中分配参数,例如“this.b = b”。对此的简写会很好,因为这是您经常想要的,但 Typescript 的设计并不是为了简洁。 (4认同)
  • 我喜欢这个解决方案 (2认同)

Pau*_*haw 6

简单参数:

constructor (private recurrenceSettings: {year?: number, month?: number, date?: number})
Run Code Online (Sandbox Code Playgroud)

private 关键字将参数实例化为实例变量,从而节省了在构造函数中实例化的需要。public如果您想实例化公共属性也可以。

像这样使用:

const recurrenceRule = new MyClass({month: 12})
Run Code Online (Sandbox Code Playgroud)

或者使用解构(用法同上):

constructor({day, month, year}: {day?: number, month?: number, year?: number})
Run Code Online (Sandbox Code Playgroud)

不过,上述版本失去了对实例变量使用私有/公共快捷方式的能力(请参阅https://github.com/Microsoft/TypeScript/issues/5326)。


pyz*_*zon 5

您也可以使用Partial来达到相同的结果。

您将以与前面的答案相同的方式实例化。

class Bar {
  year = new Date().getFullYear();
  month = new Date().getMonth();
  day = new Date().getDay();
  constructor(bar?: Partial<Bar>) {
    Object.assign(this, bar);
  }
  
  log () {
    console.log(`year: ${this.year}, month: ${this.month}, day: ${this.day}`);
  }
}

new Bar().log();
new Bar({ day: 2 }).log();
new Bar({ day: 2, month: 8 }).log();
new Bar({ year: 2015 }).log();
Run Code Online (Sandbox Code Playgroud)

注意 1.Partial<Bar>只要同名的属性具有相同的类型,就可以接受任何内容。是的,这有点违反类型安全。这仍然很强大的原因是,如果您开始使用 键入对象文字{,智能感知将告诉您可以初始化哪些属性。

注意 2.Object.assign将忽略readonly属性,因为它是 JavaScript 特定的东西,而不是 TypeScript 特定的。这意味着虽然您无法为readonly属性分配新值,但您当然可以使用Object.assign.