Scala Enthusiast
Scala Enthusiast

Reputation: 468

Is there a Declarative approach to converting each member of a TypeScipt array to a full instance of an Object?

I have a class I can't change, simplified version shown. I got an array of variations on the class. I need to add the rest of the class to each member of the array before I can use them.

class ValueType {
    name: string;
    size: number = 5;

    constructor(source?: {
        name?: string;
        size?: number;
    }) {
        if (source) {
           Object.assign(this, source);
        }
    }
};

So this can be done by adding the class to each member of the array individually, either of these two ways, but that, with a big array, is 'messy code' IMHO.

let test1 = [new ValueType({
    name: 'john',
})];

console.log('tv1 is:', test1[0].size);  // 5

// OR

let test2 = [{
    name: 'paul',
    ...new ValueType()
}];

console.log('tv2 is:', test2[0].size);  // 5

Here's my attempt at an declarative way, but it doesn't work. It doesn't allow you get the default value of the un-updated items.

let test3: Partial<ValueType>[] = [{
    name: 'tom',
}];

console.log('tv3 is:', test3[0].size); // undefined

Finally, here's an imperative approach that achieves what I want, but I can't help but think that TypeScript has a better way of doing this with types, Utility Types, ANDs, ORs, etc!

let test4: ValueType[] = [{
    name: 'tom',
}].map(value => Object.assign(value, new ValueType()));

console.log('tv4 is:', test4[0].size);

Upvotes: 1

Views: 90

Answers (1)

Riheldo Melo
Riheldo Melo

Reputation: 144

Typescript doesnt adds codes to JS Objects at runtime. So to achieve what do you want, you need to declare an factory method (check for Factory Pattern).

So, in your exemple, the factory will receive data as params, and return the instance desired. You can declare a factory function or an static factory method inside your class.

Example

Factory as Function

function factoryValueType(data: Partial<ValueType>): ValueType {
    return new ValueType(data);
}

Factory as Static Method

class ValueType {
    name: string;
    size: number = 5;

    constructor(source?: {
        name?: string;
        size?: number;
    }) {
        if (source) {
            Object.assign(this, source);
        }
    }

    static fabricate(data): ValueType {
        return new ValueType(data);
    }
}

Declaritive use to initialize an Array

valueTypeList: ValueType[] = [
    ValueType.fabricate({name: 'John'}), // use factory as static method
    factoryValueType({name: 'Doe'}), // use factory as function
]

You can utilize this to transform json objects

valueTypeList: ValueType[] = jsonList.map(obj => factoryValueType(obj));

Using factory pattern is cleaner and safier, you can debug and create test for your factories. Just remeber that there is no unique solution, this examples abouve is just one of them.

Upvotes: 1

Related Questions