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

Bru*_*oLM 12 typescript

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

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

const item = new Item(1, 1, 1);
item.id // 1
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

这可能吗?有可能吗?

做类似的事情是否有变通方法?

Tit*_*mir 14

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

Partial<T>

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

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 !')} });
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

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

第三个选项是创建一个类似于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 
Run Code Online (Sandbox Code Playgroud)

  • TS 可能会讨厌你这样使用 Object.assign 。属性“x”没有初始值设定项,并且未在 constructor.ts 中明确分配(2564) (4认同)
  • @backdesk 开一张 GH 票。该模式足够简单,易于识别,编译器可以识别该赋值。您可能还对 /sf/ask/3719012111/ 感兴趣 (2认同)