Sankalp
Sankalp

Reputation: 1350

Typescript constructor with spread operator

Need to assign porperties to the only defined from the interface if used with spread operator.

I am expecting a solution for using typescript constructor with spread operator.

For eg.

export interface IBrand {
    id: string;
    name: string;
}

export class Brand implements IBrand {
    id: string;
    name: string;       

    constructor(data: IBrand) {
        this.id = data.id;
        this.name = data.name;
    }
}

this is one option so the moment when I call this class like this, no way how many members are there but I would be having only id, name to final object.

new Brand({...data })

Case: But when I have 25+ keys to the data

export interface IBrand {
    id: string;
    name: string;
}

export class Brand implements IBrand {
    id: string;
    name: string;       

    constructor(data: Partial<IBrand>) {
        Object.assign(this, data);
    }
}

I am expecting not to write all properties again constructor. No matter it has 25 it would be just assigning that existing properties would be assigned. If data has section, genre or any other property it would be ignored.

My 2nd snippet doesn't work.

Upvotes: 10

Views: 12309

Answers (3)

bikeman868
bikeman868

Reputation: 2637

If you are willing to forego inheritance and encapsulation and embrace composition instead, then you can use types instead of classes and interfaces. IMHO this is where TypeScript really shines.

I am going to use a slightly different scenario than your Brand example, because I think it demonstrates the power of TypeScript better.

Lets start by defining two types:

type Person = {
    id: string
    name: string
}

type Editable = {
    canEdit: boolean
    save(): Promise<boolean>
}

I can compose these into a new type:

type EditablePerson = Editable & Person

This allows me to construct a new person like this:

const person: Person = { id: '12345', name: 'Martin' }

then use this person to construct an EditablePerson like this

const editablePerson: EditablePerson = {
    ...person,
    canEdit: true,
    save: () => {
        console.log(this.name)
        return Promise.resolve(true)
    }
}

I can also write an EditablePerson constructor function that uses the spread operator like this:

const EditablePerson = function(editable: Editable, person: Person): EditablePerson {
    return { ...editable, ...person }
}

Which allows me to construct an EditablePerson like this:

editablePerson = EditablePerson(
    { canEdit: true, save:() => Promise.resolve(true) }, 
    person)

Using the structured typing system in TypeScript brings you much closer to JavaScript and is less like writing in other OOP languages. I really love this style of writing TypeScript because I have long been an opponent of inheritance and always preferred composition.

Using this approach, your Brand example might look something like:

type IBrand {
    id: string
    name: string
}

type Brand = {
    brandField?: string
    brandMethod: () => string
} & IBrand

const Brand = function(brand: IBrand): Brand {
    return { ...brand, brandMethod: () => 'Hello from Brand' }
}

const myBrand: IBrand = Brand({ id: 'abc', name: 'Wonderful Products!' })

Upvotes: -1

Homer
Homer

Reputation: 7826

This doesn't use the spread operator, but you could use the method from this answer

constructor(data: IBrand) {
    for (let key in data) {
        this[key] = data[key];
    }
}

then instantiate...

new Brand(data);

Upvotes: 9

Sankalp
Sankalp

Reputation: 1350

I find a better solution for recurring code using class-transformer package. It also helps to expose and transform input into the required output.

Upvotes: 6

Related Questions