具有公开参数的构造函数分解 [英] Constructor Destructuring with exposed parameters

查看:91
本文介绍了具有公开参数的构造函数分解的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个构造函数,该构造函数使用解构来简化使用适当的默认值创建对象所需要传递的内容.

I have a constructor which uses destrucuring to simplify what needs to be passed to create the object with the proper defaults.

export class PageConfig {
  constructor({
    isSliding = false
  }: {
    isSliding?: boolean;
    getList: (pagingInfo: PagingInfo) => Observable<any>;
  }) {}
}

我想将传递给构造函数的属性公开,最好不要重新声明它们.另外,我不希望有一个中间人对象.例如,说我有一门课,可以像这样实例化我的对象:

I want to expose the properties passed into the constructor as public, preferable without redeclaring them. Additionally I would not like to have a middle man object. e.g say I had a class which instanciated my object like so:

class UsersPage {

    config = new pageConfig({ this.getList })    

    getList(pagingInfo: PagingInfo) {
      // do work...
    }
}

我希望配置公开两件事:

I would like the config to expose 2 thing:

config.getList()
config.isSliding

如何有效地做到这一点?

How can I efficiently do this?

编辑 我试图通过创建一个构造器参数和该类都继承的基类来实现此目的,但是,如果我在解构中省略了属性,则将无法在构造函数中引用它们.

EDIT I've tried to do this by creating an base class which both the consturtor arguments and the class inherits from, However, if I omit the properties in the destructuring I won't be able to reference them in the constructor.

例如

export class PageConfigArgs {
    isSliding?: boolean;
    getList: (pagingInfo: PagingInfo) => Observable<any>;
}

export class PageConfig extends PageConfigArgs {
  constructor({
    isSliding = false
  }: PageConfigArgs ) {
    super();
    this.isSliding = isSliding;
    //this fails since its not declared in the destructuring
    //However I do not want to declare it since it is required
    this.getList = getList;  
  }
}

推荐答案

TypeScript中没有简单的方法以编程方式将属性从传递给构造函数的对象复制到正在构造的对象中,并让编译器验证其安全性. 您无法做到破坏性的除非您提到名称,否则不会将名称纳入范围,即使您可以这样做,也必须将名称手动复制到构造的对象中.

There's no simple way in TypeScript to programmatically copy properties from an object passed into a constructor to the object being constructed and have the compiler verify that it's safe. You can't do it with destructuring; that won't bring names into scope unless you mention them, and that even if you could do this you'd have to manually copy them into the constructed object anyway.

与解构效果类似的功能是 Object.assign() ,因此您希望使构造函数像constructor(x: X){Object.assign(this, x)} ...一样,并且确实可以在运行时使用.但是编译器无法识别该属性实际上已经设置,并且倾向于警告您:

Similar in effect to destructuring is the function Object.assign(), so you could hope to have the constructor be like constructor(x: X){Object.assign(this, x)}... and this does work at runtime. But the compiler does not recognize that the properties have actually been set, and will tend to warn you:

class FailedPageConfig implements PageConfigArgs { // error!
  // Class 'FailedPageConfig' incorrectly implements interface 'PageConfigArgs'.
  //  Property 'getList' is missing in type 'FailedPageConfig'
  // but required in type 'PageConfigArgs'.
  constructor(config: PageConfigArgs) {
    Object.assign(this, config);
  }
}

您可以使用对于所有缺失"属性的明确赋值声明,但这是您要避免的声明,对吧?

You can manually fix that by using a definite assignment assertion for all "missing" properties, but this is a declaration you wanted to avoid, right?

class OkayPageConfig implements PageConfigArgs { 
  getList!: PageConfigArgs["getList"]; // definite assignment
  constructor(config: PageConfigArgs) {
    Object.assign(this, config);
  }
}


那么,我们还能做什么?


So, what else can we do?

我们可以做的一件事就是制作一个函数,该函数生成使用Object.assign()的类构造函数,并使用类型断言告诉编译器不要担心它无法验证安全性这一事实:

One thing we can do is make a function that generates class constructors that use Object.assign(), and use a type assertion to tell the compiler not to worry about the fact that it can't verify the safety:

function ShallowCopyConstructor<T>() {
  return class {
    constructor(x: T) {
      Object.assign(this, x);
    }
  } as new (x: T) => T; // assertion here
}

然后您可以像这样使用它:

And then you can use it like this:

export class PageConfigPossiblyUndefinedIsSliding extends ShallowCopyConstructor<
  PageConfigArgs
>() {}

declare const pcfgX: PageConfigPossiblyUndefinedIsSliding;
pcfgX.getList; // pagingInfo: PagingInfo) => Observable<any>
pcfgX.isSliding; // boolean | undefined

您可以看到,已知PageConfigPossiblyUndefinedIsSliding实例具有getListisSliding属性.当然,isSliding的类型为boolean | undefined,并且您想要一个默认的false值,这样它就永远不会是undefined,对吗?这是我们的处理方式:

You can see that PageConfigPossiblyUndefinedIsSliding instances are known to have a getList and an isSliding property. Of course, isSliding is of type boolean | undefined, and you wanted a default false value, so that it would never be undefined, right? Here's how we'd do that:

export class PageConfig extends ShallowCopyConstructor<
  Required<PageConfigArgs>
>() {
  constructor(configArgs: PageConfigArgs) {
    super(Object.assign({ isSliding: false }, configArgs));
  }
}

declare const pcfg: PageConfig;
pcfg.getList; // pagingInfo: PagingInfo) => Observable<any>
pcfg.isSliding; // boolean

此处PageConfig扩展了ShallowCopyConstructor<Required<PageConfigArgs>>(),这意味着超类的构造函数要求同时传递getListisSliding属性(使用

Here PageConfig extends ShallowCopyConstructor<Required<PageConfigArgs>>(), meaning that the superclass's constructor requires both getList and isSliding properties to be passed in (using the Required<T> utility type).

PageConfig的构造函数只需要一个PageConfigArgs,并使用另一个Object.assign()调用从中组合一个Required<PageConfigArgs>.

And the constructor of PageConfig only needs a PageConfigArgs, and assembles a Required<PageConfigArgs> from it using another Object.assign() call.

所以现在我们有了一个PageConfig类,该类的构造函数接受PageConfigArgs并构造一个Required<PageConfigArgs>.

So now we have a PageConfig class whose constructor accepts PageConfigArgs and which constructs a Required<PageConfigArgs>.

最后,我们进入您的UsersPage课堂.您不能执行new PageConfig({this.getList}).那是无效的语法.相反,您可以执行以下操作:

Finally we get to your UsersPage class. You can't do new PageConfig({this.getList}). That's not valid syntax. Instead you can do this:

class UsersPage {
  config = new PageConfig(this);

  getList(pagingInfo: PagingInfo) {
    return null!;
  }
}

或这个

class UsersPage {
  config = new PageConfig({getList: this.getList});

  getList(pagingInfo: PagingInfo) {
    return null!;
  }
}

或者,如果您不想键入单词getList两次,并且不想从this复制每个属性,则可以创建一个名为<的辅助函数. c26>将从对象中复制命名属性:

or, if you don't want to type the word getList twice, and don't want to copy every property from this, then you can make a helper function called pick which copies named properties out of an object:

function pick<T, K extends keyof T>(obj: T, ...keys: K[]) {
  const ret = {} as Pick<T, K>;
  for (const k of keys) {
    ret[k] = obj[k];
  }
  return ret;
}

然后使用它:

class UsersPage {
  config = new PageConfig(pick(this, "getList"));

  getList(pagingInfo: PagingInfo) {
    return null!;
  }
}


好的,那里有很多东西可以打开.希望它能给您一些指导.祝你好运!


Okay there's a lot to unpack there. Hope it gives you some direction. Good luck!

链接到代码

这篇关于具有公开参数的构造函数分解的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆