如何使用定义类字段的对象构建 TypeScript 类构造函数? [英] How to build a TypeScript class constructor with object defining class fields?

查看:24
本文介绍了如何使用定义类字段的对象构建 TypeScript 类构造函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在 TypeScript 中,可以创建一个带有构造函数的类,该构造函数接受带有访问修饰符的参数,并自动转换类字段中的这些参数.

In TypeScript it's possible to create a class with a constructor that takes parameter with access modifiers and it automatically convert those parameters in class fields.

class Item {
  constructor(
    public id: number,
    public updatedAt: number,
    public createdAt: number,
  ) {}
}

const item = new Item(1, 1, 1);
item.id // 1

我想知道是否有办法在一个对象中传递所有这些参数

I'm wondering if there is a way to pass all those parameters in an object instead

class Item {
  constructor({
    public id: number,
    public updatedAt: number,
    public createdAt: number,
  }) {}
}

const item = new Item({ id: 1, updatedAt: 1, createdAt: 1 });
item.id // 1

这可能吗?永远有可能吗?

Is this possible? Ever gonna be possible?

是否有解决方法可以做类似的事情?

Are there workarounds to do something similar?

推荐答案

最简单的方法是在类中声明字段并使用映射类型作为参数,然后使用 Object.assign将字段分配给 this.对于要使用的映射类型,我们有几个选项:

The simplest way would be to declare the fields in the class and use a mapped type as a parameter, then use Object.assign to assign the fields to this. We have several options for which mapped type to use:

部分

Type 将包含类的所有成员(字段和方法),但它们都是可选的.这里的缺点是我们不能使某些字段成为必需的,并且调用者可能会覆盖一个方法

Type will contain all members (fields and methods) of the class but all of them are optional. The disadvantage here is we can't make some of the fields required, and the caller can potentially override a method

class Item {

    public id: number;
    public updatedAt: number;
    public createdAt: number;
    constructor(data: Partial<Item>) {
        Object.assign(this, data);
    }
    method() {}
}

//Works 
const item = new Item({ id: 1, updatedAt: 1, createdAt: 1 });
//This also works unfortunately 
const item2 = new Item({ id: 1, method() { console.log('overriden from param !')} });

选择

这个映射类型允许我们通过指定几个作为 T 键的字符串文字类型的联合来从 T 中挑选一些属性.优点是 Pick 将从类中的原始声明中继承该字段是否是必需的(因此某些字段可以是必需的,而另一些是可选的)并且由于我们指定了我们选择的成员,我们可以省略方法.缺点是我们必须写两次属性名称(一次在类中,一次在Pick中):

This mapped type allows us to pick some properties from T by specifying a union of several string literal types that are keys of T. The advantages are that Pick will inherit whether the field is required or not from the original declaration in the class (so some fields can be required and other optional) and since we specify which members we pick, we can omit methods. The disadvantage is that we have to write property names twice (once in the class and once in the Pick):

class Item {
    public id: number;
    public updatedAt?: number;
    public createdAt?: number;
    constructor(data: Pick<Item, "id" | "updatedAt" | "createdAt">) {
        Object.assign(this, data);
    }
    method() {}
}
const item = new Item({ id: 1  }); //id is required others fields are not
const item2 = new Item({ id: 1, method() {}  }); // error method is not allowed

删除方法的自定义映射类型

第三个选项是创建一个类似于 Pick 的类型,它包括所有类字段,但不自动包含方法.我们可以在 Typescript 2.8 中使用条件类型(在撰写本文时未发布,但应该在 2018 年 3 月发布,您现在可以通过 npm install -g typescript@next 获得它).这具有 Pick 的优点,无需再次指定文件名:

The third option would be create a type similar to Pick that includes all class fields but not the methods automatically. We can do this in Typescript 2.8 using conditional types (unrelease at the time of writing, but should be release in March 2018, you can get it right now via npm install -g typescript@next). This has the advantages of Pick without the need to specify filed names again:

type NonMethodKeys<T> = ({[P in keyof T]: T[P] extends Function ? never : P } & { [x: string]: never })[keyof T];  
type RemoveMethods<T> = Pick<T, NonMethodKeys<T>>; 

class Item {
    public id: number;
    public updatedAt?: number;
    public createdAt?: number;
    constructor(data: RemoveMethods<Item>) { // No need to specify field names again
        Object.assign(this, data);
    }
    method() {}
}

const item = new Item({ id: 1  });  //id is required others fields are not
const item2 = new Item({ id: 1, method() {}  }); // error method is not allowed 

这篇关于如何使用定义类字段的对象构建 TypeScript 类构造函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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