JohnWeisz/TypedJSON

jsonMember could not resolve detected property constructor at runtime.

chetankhargone opened this issue · 10 comments

I am using TypedJSON in my Angular 8 app.

Below is how my model looks like

import  'reflect-metadata';
import { jsonObject, jsonMember } from "typedjson";


@jsonObject
export class APIResponse {
@jsonMember
HttpStatusCode?: number;
@jsonMember
Message?: string;
@jsonMember
Data?: any;
}

But this is throwing the below error for each property.

jsonMember on APIResponse.HttpStatusCode: could not resolve detected property constructor at runtime.

Going through the Github link, I modified the above class as

@jsonObject
export class APIResponse {
@jsonMember({ constructor: Number })
HttpStatusCode?: number;
@jsonMember({ constructor: String})
Message?: string;
@jsonMember({ constructor: Object})
Data?: any;

}

But then it throws the error as

Right-hand side of 'instanceof' is not an object
at isSubtypeOf (typedjson.js:166)

How to get rid of this error?

Thanks!

Hey Chetankhargone,

Are you sure that this is the complete case that is causing you trouble? I tried different inputs and both examples seem to work fine for me.

Maybe it is something similar to #108 ?

Hello @Neos3452 ,
Thanks for the follow-up. It would be really great if you could please share the examples that you tried.

Mine is fresh Angular 8 app. Below are relevant dependencies

"@angular/common": "~8.2.3", "@angular/compiler": "~8.2.3", "@angular/core": "~8.2.3", "reflect-metadata": "^0.1.13", "rxjs": "~6.4.0", "tslib": "^1.10.0", "typedjson": "^1.4.0", "zone.js": "~0.9.1"

I actually did not include angular in the examples I tried. I took your classes with the same annotations and tried to parse/stringify some objects. That’s why I mentioned another issue, because it was also a problem with typedjson in angular 8.

Could you create a sample repo illustrating the problem?

I am having absolutely the same problem with typedjson in Angular 8 (I had no problem with typedjson in Angular 7 before). You can check out the sample repo from here: https://github.com/nam-vuhoang/test-typed-json.

I added this line to my polyfills.ts as recommended in #108 , but it didn't help:
import 'core-js/proposals/reflect-metadata';

====

category-entity.ts
`import 'reflect-metadata';
import { jsonObject, jsonMember } from 'typedjson';

@JsonObject
export class CategoryEntity {
@jsonMember({ constructor: String })
name: string;
}`

app.component.ts
import { TypedJSON } from 'typedjson'; import { CategoryEntity } from './types/category-entity'; ... category = new TypedJSON(CategoryEntity).parse('{"name": "foo"}')

package.json
{ "name": "test-typed-json", "version": "0.0.0", "scripts": { "ng": "ng", "start": "ng serve", "build": "ng build", "test": "ng test", "lint": "ng lint", "e2e": "ng e2e" }, "private": true, "dependencies": { "@angular/animations": "~8.2.11", "@angular/common": "~8.2.11", "@angular/compiler": "~8.2.11", "@angular/core": "~8.2.11", "@angular/forms": "~8.2.11", "@angular/platform-browser": "~8.2.11", "@angular/platform-browser-dynamic": "~8.2.11", "@angular/router": "~8.2.11", "reflect-metadata": "^0.1.13", "rxjs": "~6.4.0", "tslib": "^1.10.0", "typedjson": "^1.5.0", "zone.js": "~0.9.1" }, "devDependencies": { "@angular-devkit/build-angular": "~0.803.13", "@angular/cli": "~8.3.13", "@angular/compiler-cli": "~8.2.11", "@angular/language-service": "~8.2.11", "@types/node": "~8.9.4", "@types/jasmine": "~3.3.8", "@types/jasminewd2": "~2.0.3", "codelyzer": "^5.0.0", "jasmine-core": "~3.4.0", "jasmine-spec-reporter": "~4.2.1", "karma": "~4.1.0", "karma-chrome-launcher": "~2.2.0", "karma-coverage-istanbul-reporter": "~2.0.1", "karma-jasmine": "~2.0.1", "karma-jasmine-html-reporter": "^1.4.0", "protractor": "~5.4.0", "ts-node": "~7.0.0", "tslint": "~5.15.0", "typescript": "~3.5.3" } }

Just in case, if you want to compare with Angular 7 package.json (where typedjson worked perfectly):

"dependencies": { "@angular/animations": "^7.2.15", "@angular/cdk": "~7.3.7", "@angular/common": "^7.2.15", "@angular/compiler": "^7.2.15", "@angular/core": "^7.2.15", "@angular/forms": "^7.2.15", "@angular/material": "^7.3.7", "@angular/platform-browser": "^7.2.15", "@angular/platform-browser-dynamic": "^7.2.15", "@angular/router": "^7.2.15", "angular2-cookie-law": "^6.2.0", "angular2-multiselect-dropdown": "^4.6.3", "chart.js": "^2.8.0", "color-convert": "^2.0.1", "colors": "^1.3.3", "core-js": "^2.6.5", "fast-json-stable-stringify": "^2.0.0", "hammerjs": "^2.0.8", "ngx-avatar": "^3.7.0", "ngx-lightbox": "^1.2.0", "reflect-metadata": "^0.1.13", "rxjs": "~6.3.3", "tslib": "^1.10.0", "typed-countries": "^1.1.1", "typedjson": "^1.4.0", "zone.js": "~0.8.26" }, "devDependencies": { "@angular-devkit/build-angular": "^0.13.9", "@angular/cli": "^7.3.9", "@angular/compiler-cli": "^7.2.15", "@angular/language-service": "^7.2.15", "@types/jasmine": "~2.8.8", "@types/jasminewd2": "~2.0.3", "@types/node": "^8.10.47", "codelyzer": "~4.5.0", "jasmine-core": "~2.99.1", "jasmine-spec-reporter": "~4.2.1", "karma": "~4.0.0", "karma-chrome-launcher": "~2.2.0", "karma-coverage-istanbul-reporter": "^2.0.6", "karma-jasmine": "~1.1.2", "karma-jasmine-html-reporter": "^0.2.2", "protractor": "~5.4.0", "ts-node": "~7.0.0", "tslint": "~5.11.0", "typescript": "~3.2.2" }

Hi, here is some additional info for you to consider and find out the root cause:

In Angular 8.2.11, typescript 3.5.3, core-js 3.2.1 is automatically used (because it is defined as a dependency in @angular-devkit). Unlike its previous versions, core-js@3 contains core-js/proposals/reflect-metadata, so no matter if reflect-metadata is installed separately or not, the Reflect class from core-js is always used. And this method Reflect.getMetadata("design:type", target, _propKey) (used in typedjson.js in typedjson^1.5.0, line 1533) for some reason always returns undefined, when target is CategoryEntity and _propKey is "name" (see the example above).

For comparison, with Angular 7, typesscript 3.2.2, core-js 2.6.5 (doesn't contain reflect-metadata!!), reflect-metadata 0.1.13, the function mentioned above returns function String().

Hey @nam-vuhoang, thanks a lot for the repo and analysis it really helped me to quickly narrow down the problem. It seems Angular 8 has a different configuration than before that needs an adjustment for TypedJSON. I created a PR for your test repo so you can test it your self (should work with ng serve and in --prod). I also updated the readme.

I accepted the PR on my repo. It works perfectly now! Thank you very much! :)

Hi @Neos3452 , there is error "object doesn't support property or method 'includes'" when running in IE, because IE doesn't support Array.includes (see documentation here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes).

As suggested here: https://stackoverflow.com/questions/56956996/angular-8-runtime-error-after-core-js-upgrade, we need to add to polyfills.ts:

import 'core-js/es';
import 'core-js/proposals/reflect-metadata';

And what's very important, 'core-js/es' must be imported before importing 'zone.js' in Angular. See modified polyfills.ts here: https://github.com/nam-vuhoang/test-typed-json/blob/master/src/polyfills.ts.

Please update readme. :)

I actually just removed Array.includes() which is not strictly necessary. Hope this helps :)