If you're declaring a class
without the intent to use instanceof
or member methods, what you most likely want is just an interface
, which would also happen to simplify your logic. The only downside with an interface is that you can't use field initializers like enabled: boolean = true;
export interface Tax {
name: string;
description?: string;
value: number;
enabled?: boolean;
}
...
const entity: Tax = this.form.value/* as Tax */;
In TypeScript, this is the more conventional solution to your problem, since the only purpose of your awkward Object.assign(new Tax(), ...)
was to satisfy the type-check of your class
declaration when you really just needed an interface
instead.
If in fact you do need to use instanceof
or member methods, I would instead suggest adding an analogous interface
, and create a constructor
for your class:
export interface ITax {
name: string;
description?: string;
value: number;
enabled?: boolean;
}
export class Tax implements ITax {
name: string;
description: string | undefined;
value: number;
enabled: boolean;
constructor ({ name, description, value, enabled = true }: ITax) {
this.name = name;
this.description = description;
this.value = value;
this.enabled = enabled;
}
};
...
const entity: Tax = new Tax(this.form.value/* as ITax */);
This way, you're not lying about the type of this.form.value
or entity
.
Some would argue that it's bad practice to have interfaces with I
prefixes in TypeScript, but in this particular case I would argue it makes sense to have because your this.form.value
is a plain object that implements the interface, while Tax
denotes a proper instance of the respective class, which allows language constructs like instanceof
checks, access to member methods, etc., that are not part of the base interface ITax
.