Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fill properties of class TypeScript?

Lets assume there is a model class like:

class Filter implements IFilterJournal {
  public category: number;
  public subject: number;
  public teacher: number;
  public mark: number;
}

I can create instance of this class:

let f = new Filter();

It returns object Filter with empty properties inside.

How to fill properties of class more convenient?

I can determine consturctor like:

public constructor(public category: number, public subject: number, public teacher: number, public mark: number){
}

Then at the time of creation instance pass parameters:

let f = new Filter(1, 2, 3, 4)

But what if I need to fill only public subject: number; property? either others? How to fill them selectively?

Another was is to make parameters as optional:

public constructor(public category?: number, public subject?: number, public teacher?: number, public mark?: number){}

Then use this like:

let f = new Filter(subject = 1);
like image 302
OPV Avatar asked May 29 '18 12:05

OPV


3 Answers

If you can initialize the object with any combination of properties, you can use a constructor that takes Partial<Filter> as an argument, and uses Object.assign to set the fields on the object.

class Filter  {
    constructor(data: Partial<Filter>){
        Object.assign(this, data);
    }
    public category: number;
    public subject: number;
    public teacher: number;
    public mark: number;
}
new Filter({ category: 0})
new Filter({ category: 1, subject: 2, teacher: 3, mark: 4})

Note Partial is a mapped type that keeps the members of a type but marks all of them as Partial. See docs. In this case Partial<Filter> is equivalent to:

interface PartialFilter{
    category?: number;
    subject?: number;
    teacher?: number;
    mark?: number;
}

If your type has methods, Partial would allow the argument to the constructor to contain those methods, this may be an issue. You can use conditional types to filter out methods from the argument, but it's a bit more complicated:

type NotFunctions<T> = { [P in keyof T]: T[P]  extends Function ? never : P }[keyof T];
class Filter  {
    constructor(data: Partial<Pick<Filter, NotFunctions<Filter>>>){
        Object.assign(this, data);
    }
    public category: number;
    public subject: number;
    public teacher: number;
    public mark: number;

    public sayHi(){ return "Hi" }
}
new Filter({ category: 0, sayHi: ()=> {}}) //Error with new constructor argument type 
new Filter({ category: 0})
new Filter({ category: 1, subject: 2, teacher: 3, mark: 4})
like image 167
Titian Cernicova-Dragomir Avatar answered Oct 13 '22 00:10

Titian Cernicova-Dragomir


Like C# class:

export class Filter {
    category: number = null;
    subject: string = null;
    teacher: number = null;
    mark: boolean = null;

public constructor(init?: Partial<Filter>) {
    Object.assign(this, init);
}}

When you create a new instance all field names are disponible and empty.

const instance_of_filter: Filter = new Filter();

you have now a class with all fields defined :

instance_of_filter {
    "category": null,
    "subject": null,
    "teacher": null,
    "mark": null
}
like image 31
spec Avatar answered Oct 13 '22 00:10

spec


You don't have to fill all the object properties right off that bat.

public constructor(public _category: number){
    category = _category;
}

Would work just fine. Just keep in mind that those properties you don't fill will be undefined if you call them later before assigning them, so at the very least you may want to initialize them to some sort of acceptable value. Perhaps:

public constructor(public _category: number){
    this.category = _category;
    this.subject = 0;
    this.teacher = 0;
    //etc...
}
like image 40
Sprawl63 Avatar answered Oct 12 '22 23:10

Sprawl63