Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript spead operator on object with method

In my angular project I have an object which contains a type and status field. The status can vary based on the type. One could argue that this is bad design, but that's the way it is for now. The point is I can't seem to use the spread operator on this object, because the compiler says Property 'getStatusList' is missing in type ...

I simplified the class, but it would look something like this:

export class Foo {
    constructor(
        public type: number,
        public status: number
    ) { }

    getStatusList(): string[] {
        switch (this.type) {
            case 3: {
                return ['Off', 'Interval', 'On Hold']
            }

            default: {
                return ['Off', 'On']
            }
        }
    }
}

This is with typescript 2.9.2 and angular cli 6.1.1

The code below would trigger the error, but while writing the example code in typescript playground I figured maybe I should use Object.assign. Although I still thought I could simply overrule some properties of an object using the spread operator?

const oldFoo: Foo = new Foo(3, 5);
console.log('old status: ', oldFoo.status);

const newFoo: Foo = { ...oldFoo, type: 1, status: 7 };
console.log('new status: ', newFoo.status);
like image 349
rolandow Avatar asked Nov 07 '22 04:11

rolandow


1 Answers

When you use the spread operator in object literals, you are not going to get an object of the same class as the original. From the documentation:

[The spread operator] copies own enumerable properties from a provided object onto a new object.

Shallow-cloning (excluding prototype) or merging of objects is now possible using a shorter syntax than Object.assign().

So you are just "shallow-cloning" oldFoo. You will miss anything on the prototype, such as methods. If you want to have an actual Foo object, you should probably construct one. Once you have constructed it you can use Object.assign() to set multiple properties at once, but if you're using a constructor anyway I guess you should just pass the right parameters to the constructor in the first place.


You could copy the prototype instead:

const newFoo  = { ...oldFoo, type: 1, status: 7 } as Foo;
Object.setPrototypeOf(newFoo, Object.getPrototypeOf(oldFoo));

and this would likely work, but messing with prototypes is not something I'd do lightly.


Hope that helps. Good luck!

like image 62
jcalz Avatar answered Nov 14 '22 22:11

jcalz