打字稿:通过传入命名参数的构造函数创建类?

Posted

技术标签:

【中文标题】打字稿:通过传入命名参数的构造函数创建类?【英文标题】:Typescript: Create class via constructor passing in named parameters? 【发布时间】:2018-01-12 10:18:11 【问题描述】:

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

constructor(year?: number,
            month?: number,
            date?: number)

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

  const recurrenceRule = new MyNewClass(month: 6)

但是没用,我试过了

  const recurrenceRule = new MyNewClass(month = 6)

那没用。

我让它工作的唯一方法是

  const recurrenceRule = new MyNewClass(undefined, 4)

  const recurrenceRule = new MyNewClass(, 4)

但它看起来很乱,我希望传递命名参数,因为它们都是可选的,我应该能够只传递 1 - 对吧?

【问题讨论】:

我知道的唯一具有此功能的语言是 Swift 和 Python 你可以传入一个接口对象,但是就像@Vivick说的,这个功能在TS中是不存在的 @Vivick C# 也有很长一段时间了。 【参考方案1】:
class Bar 
  constructor(a, b: a?: number, b?: number) 


new Bar(b: 1)

有关详细信息,请参阅ES6 Object Destructuring with functions。

【讨论】:

我喜欢这个解决方案【参考方案2】:

您可以使用 ES6 中引入的对象解构来归档所需的行为: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()
             = )

允许分别使用 0、1、2 或 3 个参数调用构造函数(参见下面的 sn-p)。

有点神秘的= 是针对您创建没有任何参数的新实例的情况。首先, 被用作参数对象的默认值。然后,由于缺少year,因此添加了该默认值,然后分别添加月份和日期。

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

constructor( year = new Date().getFullYear(),
              month = new Date().getMonth(),
              day = new Date().getDay()
:  year?: number, month?: number, day?: number  = )  
    ...                

虽然这个真的看起来很神秘。

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

【讨论】:

【参考方案3】:

简单参数:

constructor (private recurrenceSettings: year?: number, month?: number, date?: number)

private 关键字将参数实例化为实例变量,无需在构造函数中实例化。如果你想实例化公共属性,也可以是public

这样使用:

const recurrenceRule = new MyClass(month: 12)

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

constructor(day, month, year: day?: number, month?: number, year?: number)

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

【讨论】:

【参考方案4】:

您也可以使用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();

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

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

【讨论】:

【参考方案5】:

在某些情况下,拥有一个界面和单独的制造商功能会更容易。 (供未来的读者阅读。)


interface Foo 
  x: number
  y: number


function newFoo(x=5,y=10) : Foo return x,y

const f = newFoo(x:100)

【讨论】:

以上是关于打字稿:通过传入命名参数的构造函数创建类?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Webpack 中禁用重命名函数名?打字稿,Javascript

通过子类化修改命名元组的构造函数参数?

打字稿:通过打字重命名obj属性

从类创建派生类型,但省略构造函数(打字稿)

如何在具有角度注入参数的打字稿中创建新对象

打字稿:类方法中的函数参数比父类中的参数更窄