如何使用定义类字段的对象构建TypeScript类构造函数?

时间:2018-03-02 02:16:42

标签: typescript

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

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

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

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

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

这可能吗?有可能吗?

是否有类似的工作方法?

3 个答案:

答案 0 :(得分:9)

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

<强> Partial<T>

Type将包含该类的所有成员(字段和方法),但所有成员都是可选的。这里的缺点是我们无法创建所需的某些字段,调用者可能会覆盖方法

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 !')} });

<强> Pick<T, K>

这种映射类型允许我们通过指定T的键的几个字符串文字类型的并集来从T中选择一些属性。优点是Pick将继承该类是否需要来自类中的原始声明(因此可能需要某些字段和其他可选项),并且由于我们指定了我们选择的成员,因此我们可以省略方法。缺点是我们必须写两次属性名称(一次在类中,一次在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的优点,而无需再次指定字段名称:

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 

答案 1 :(得分:2)

您可以通过创建界面来实现类似的行为:

interface IProps {
  id: number;
  updatedAt: number;
  createdAt: number;
}

class Item {
  constructor(public props: IProps) {}
}

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

答案 2 :(得分:0)

  

对象解构是最佳选择

class Item {
    public id: number;
    public updatedAt: number;
    public createdAt: number;

    constructor({
        id,
        updatedAt,
        createdAt,
    }: { id: number, updatedAt: number, createdAt: number }) {
        this.id = id;
        this.updatedAt = updatedAt;
        this.createdAt = createdAt;
    }
}

var item = new Item({ id: 1, updatedAt: 3, createdAt: 4 });

console.log(item.id);