SebastianG
SebastianG

Reputation: 9554

Ensure my function returns mutated object as instanceof the same class typescript?

export const FilterUndefined = <T extends object>(obj: T): T => {
  return Object.entries(obj).reduce((acc, [key, value]) => {
    return value ? { ...acc, [key]: value } : acc;
  }, {}) as T;
};

I'm migrating a database and part of cleaning up the old data structure, some of the values for some keys end up being literaly undefined. The key will still exist and will have the value undefined

I made this function but after modifying a class object with it, it will no longer be an instanceof the same class. How could I make this return an object that's instanceof the same class as the input parameter?

The as T makes TS compiler shut up but that's it.

I've also tried to get the prototype of that object and return new prototype(obj) or return new prototype.constructor(obj)

The console log of the prototype looks like this:

PROTOTYPE TestClass {}

I'm testing using this setup:

  it('should return the same type that it receives', () => {
    class TestClass {
      name: string;
      optionalProperty?: any;
    }

    let testObject = new TestClass();
    testObject.name = 'My Name';
    testObject.optionalProperty = undefined;

    console.log(testObject instanceof TestClass);
    testObject = FilterUndefined(testObject);

    console.log(testObject instanceof TestClass);
    console.log(testObject);

    expect(testObject).instanceOf(TestClass);
  });

EDIT: JSFiddle: https://jsfiddle.net/3sdg98xt/2/ but copy-pasted from vscode without any issues running it i'm getting an error 'execpted expression, got ';'

Upvotes: 5

Views: 1405

Answers (2)

Naman Kheterpal
Naman Kheterpal

Reputation: 1840

Yes, with each iteration of reduce you are returning a new {} which is an instance Object.

So to make the return object of same instace as of argument you should make following changes.

export const FilterUndefined = (obj) => {
return Object.entries(obj).reduce((acc, [key, value]) => {
    if (value) {acc[key] = value;}
    else {delete acc[key]}
    return  acc;
  }, new obj.constructor);
};

or you can use new obj.__proto__.constructor as per the target of typescript output you are using.

Reply in case you have typescript issues with this code snippet.

Upvotes: 0

carlosvin
carlosvin

Reputation: 979

This solution will mutate the input object by removing the keys with undefined values.

function removeUndefined <T>(object: T): T {
    for (const id in object) {
       if (object[id] === undefined) {
          delete object[id];
       }
    }
    return object;
}

It seems it works for your test case: Test in typescript playground

Upvotes: 1

Related Questions