JohnWeisz/TypedJSON

Add Getter/Setter in IJsonMemberOptions

Closed this issue · 2 comments

Hi,
I'm working with Vue 3 and the @vue/reactivity package. My data objects often look like this:

export class Trait {
  public name: Ref<string> = ref('')
  public value: Ref<string> = ref('')
}

where the Ref<T> type is a vue specific thing to tell the UI when something changed. Right now, if I want to serialize this, I would have to write code somehting like this:

@jsonObject
export class Trait {
  @jsonMember({ constructor: String, name: 'name' })
  private get json_name(): string {
    return this.name.value
  }

  private set json_name(newValue: string) {
    this.name.value = newValue
  }

  @jsonMember({ constructor: String, name: 'value' })
  private get json_value(): string {
    return this.value.value
  }

  private set json_value(newValue: string) {
    this.value.value = newValue
  }

  public name: Ref<string> = ref('')
  public value: Ref<string> = ref('')
}

The Ref<T> type is no class and also out of my reach since it comes from a framework. I also tried using an options object with a deserializer/serializer combo. Problem here is that a Ref<T> may contain any object not just primitives (as shown in this example).

A possible solution might look something like this:

import { myCustomRefOptions } from '@/helpers'
export class Trait {
  @jsonMember({ constructor: String, getter: (member) => member.value, setter(member, newValue ) => { member.value = newValue  })
  public name: Ref<string> = ref('')

  @jsonMember(myCustomRefOptions)
  public value: Ref<string> = ref('')
}

The difference between this and the de/serializer properties is that the return value of the getter still needs to be serialized and the newValue in the setter already was parsed.

Or maybe this is already possible and I just dont know how to do it?

Hi @DesselBane, I am not sure if I understood your problem correctly. But if you just want to serialise the inner value, you can always call TypedJSON from within the serialiser/deserialiser like below. Let me know if this helps you.

    @jsonObject
    class Person {
        @jsonMember
        firstName: string;

        @jsonMember
        lastName: string;

        getFullName() {
            return `${this.firstName} ${this.lastName}`;
        }
    }

    interface Ref<T> {
        value: T;
    }

    function serializeRef<T>(type: Serializable<T>, ref: Ref<T>): any {
        return TypedJSON.toPlainJson(ref.value, type);
    }

    function deserializeRef<T>(type: Serializable<T>, value: any): Ref<T> {
        return { value: TypedJSON.parse(value, type) }
    }



    @jsonObject
    class ContainsRefs {
        @jsonMember({serializer: ref => serializeRef(String, ref), deserializer: json => deserializeRef(String, json)})
        refStr: Ref<string>;

        @jsonMember({serializer: ref => serializeRef(Person, ref), deserializer: json => deserializeRef(Person, json)})
        refObj: Ref<Person>;
    }

Hi thanks for the reply. It seems to be working 👍 🥇