TypedJSON
TypedJSON copied to clipboard
Unexpected type hint required for Date member
It seems from the tests that members of Date type should be automatically deserialized without type hint. However, it didn't deserialize as Date but Object which turns out be something like
new Object('2016-07-29')
Without type hint: deserialize as object
@JsonObject
export class Team {
@JsonMember
public createdAt: Date;
}
let json = { createdAt: '2016-07-29' };
let str = JSON.stringify(json);
TypedJSON.parse(str, Team);
With type hint: deserialize as Date
@JsonObject
export class Team {
@JsonMember({ type: Date })
public createdAt: Date;
}
Unless I'm missing something, this seems like an issue with TypeScript itself. A string in JSON should deserialize as a Date object if that's the expected type, in which case the Date constructor will be called with the string present in the JSON -- so unless a bug is lurking somewhere affecting this behavior, the problem is caused by TypeScript by not emitting the correct type metadata. I should really add an extensive test-suite for all possible setups, including native types -- something for which I'll have time soon.
Using the type: Date hint on the JsonMember annotation for attributes of type Date causes TypedJSON to emit the following warning in the console:
@JsonMember: 'type' specified for 'MyClass.date_joined' does not match detected type.
The date value from the input JSON is still correctly deserialized into a proper Date instance. Would there be a way to prevent that warning from being output?
I tracked that down to the metadata being improperly generated in the transpiled javascript:
__decorate([
typed_json_1.JsonMember,
__metadata('design:type', Object)
], MyClass.prototype, "date_joined", void 0);
It looks like that behaviour could be related to the use of awesome-typescript-loader for webpack but not to TypeScript itself:
https://github.com/s-panferov/awesome-typescript-loader/issues/214
Well that explains a few things. Thank you for taking the time to look around.
Knowing the above, it would be nice to be able to suppress that warning from being output on the console when the type declared in metadata does not match the user-declared type.
Maybe this warning isn't needed? https://github.com/JohnWhiteTB/TypedJSON/blob/master/src/typed-json.ts#L825
I believe an acceptable behaviour would be to assume the user is correct when explicitly declaring a type using the type attribute on @JsonMember annotation, and use the declared type's constructor anyways... like it's doing right now.
I decided on removing the warning for now, as it is likely that upon encountering a TypeError during deserialization a user would first check their @JsonMember declaration.
The new version will once again display warnings, but only if the set type option is not a subtype of the detected type. This should never warn about false positives, as everything is a subtype of Object.
I would be useful to be able to somehow set global type hints or global type converters, although I'm not sure if this could work with the metadata after compilation.
For example when I'm using the following generic class, sometimes I'd like to use MinMax<number> and sometimes MinMax<Date>, but at the moment I don't know how I can use the Date one as there's no way for me to add @JsonMember({type:Date}).
@JsonObject
export class MinMax<T> {
@JsonMember
public min: T;
@JsonMember
public max: T;
constructor(min?: T, max?: T) {
this.min = min;
this.max = max;
}
}
@timfish Generic class support is something that's completely impossible to achieve without having to manually specify the constructor of the generic type as well.
As such, this is not currently planned to be available in TypedJSON 1.0.0, although it is likely to appear in the future, if the type-metadata system in TypeScript remains as rudimentary and primitive as it is today.
@timfish However, constraining the generic type to a base-class should work, if the possible sub-types are also specified through the knownTypes setting.