Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: builds fail with Angular 5 and Angular CLI when @Type is used #108

Closed
philippd opened this issue Nov 6, 2017 · 30 comments
Closed

fix: builds fail with Angular 5 and Angular CLI when @Type is used #108

philippd opened this issue Nov 6, 2017 · 30 comments
Labels
status: invalid Issues with no action to take type: fix Issues describing a broken feature.

Comments

@philippd
Copy link

philippd commented Nov 6, 2017

After upgrading to Angular 5 and Angular CLI 1.5.0, my production builds stopped working. It took me quite some time to figure out, that using the @Type decorator from class-transformer lead to the following error message when running ng build -prod:

ERROR in Error: TypeError: Cannot read property 'kind' of undefined
    at nodeCanBeDecorated (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:7805:35)
    at nodeIsDecorated (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:7825:16)
    at nodeOrChildIsDecorated (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:7829:16)
    at Object.forEach (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:1506:30)
    at Object.childIsDecorated (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:7835:27)
    at getClassFacts (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:51088:20)
    at visitClassDeclaration (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:51113:25)
    at visitTypeScript (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:50972:28)
    at visitorWorker (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:50785:24)
    at sourceElementVisitorWorker (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:50817:28)
    at saveStateAndInvoke (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:50738:27)
    at sourceElementVisitor (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:50799:20)
    at visitNodes (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:49280:48)
    at Object.visitLexicalEnvironment (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:49313:22)
    at visitSourceFile (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:51059:53)
    at saveStateAndInvoke (/demo/angular5-ct/node_modules/typescript/lib/typescript.js:50738:27)

As soon as I removed @Type, the build was working fine again. I have no idea where this has to be fixed, but hoped that maybe someone here knows what I can do to be able to use the latest Angular version with class-transformer.

I have created a simple demo project here: https://github.com/philippd/angular5-ct
Just run ng build -prod to see the error.

@Petr0vi4
Copy link

Petr0vi4 commented Nov 6, 2017

Workaround is available angular/angular#20216

@lordazzi
Copy link

lordazzi commented Nov 6, 2017

Same problem here

@niveo
Copy link

niveo commented Nov 7, 2017

Same problem with typescript 2.4.2

@sandcake
Copy link

sandcake commented Nov 9, 2017

From the workaround mentioned in angular/angular#20216
For now using:

class Type {
}

function getter() {
  return Type;
}

class Foo {
  @Type(getter)
  public ofType;
}

instead of :

class Type {
}

class Foo {
  @Type(() => Type)
  public ofType;
}

works

@adrianbenjuya
Copy link

Hi, same problem here, and thanks for the workaround, it works! want to know if there's gonna be a fix in next releases?

@niveo
Copy link

niveo commented Nov 22, 2017

@rmrevin
Copy link

rmrevin commented Nov 25, 2017

@sandcake Can be made more universal, I came to this solution (this works on angular 5):

export function serializeType<T>(object: T) {
  return function () { return object; }
}

export class CatalogItem {

  id: string;

  @Type(serializeType(CatalogCategory))
  category?: CatalogCategory = null;

  @Type(serializeType(PackingVariant))
  packing: PackingVariant;

  price: string = null;

}

@elvisbegovic
Copy link

elvisbegovic commented Nov 28, 2017

@rmrevin I dont understand whats wrong
image

and simply use them
image

any workaround?

@rmrevin
Copy link

rmrevin commented Nov 28, 2017

@istiti I don't understand your question

@elvisbegovic
Copy link

elvisbegovic commented Nov 28, 2017

Since angular5 cli1.5.4 i get same error « ...kind of undefined » due to decorator and I don’t understand your workaround comparing my case

@rmrevin

@rmrevin
Copy link

rmrevin commented Nov 28, 2017

@istiti This solution for one particular case for the library class transformer.
In your case you need to understand what exactly is causing the error.

@okodo
Copy link

okodo commented Nov 28, 2017

Have any one a workaround for @Transform decorator too?

e.g.

@Transform(value => value ? moment(value) : '', { toClassOnly: true })
updated_at: Moment;

raises the error of typescript too.

@rmrevin Your solution works. Thanks!

@jpduckwo
Copy link

@okodo e.g.

export function unixToMoment() {
  return value => moment.unix(value);
}
...
  @Transform(unixToMoment(), { toClassOnly: true })
  createdDate: Moment;

@niveo
Copy link

niveo commented Dec 15, 2017

angular/angular-cli#8434

@gmavritsakis

I had the same issue with:
Angular CLI 1.6.1
Typescript 2.4.2
Angular 5.0.2

Found a solution by changing typescript.js for now.
Replace all the function
function nodeCanBeDecorated(node)
with the following code

function nodeCanBeDecorated(node) {
       switch (node.kind) {
           case 229 /* ClassDeclaration */:
               // classes are valid targets
               return true;
           case 149 /* PropertyDeclaration */:
               // property declarations are valid if their parent is a class declaration.
   			// return node.parent.kind === 229 /* ClassDeclaration */;
   			return (node.parent && node.parent.kind === 229) || (node.original && node.original.parent && node.original.parent.kind === 229);
           case 153 /* GetAccessor */:
           case 154 /* SetAccessor */:
           case 151 /* MethodDeclaration */:
               // if this method has a body and its parent is a class declaration, this is a valid target.
               return node.body !== undefined &&
   				// && node.parent.kind === 229 /* ClassDeclaration */;
   				(node.parent && node.parent.kind === 229) || (node.original && node.original.parent && node.original.parent.kind === 229);
           case 146 /* Parameter */:
               // if the parameter's parent has a body and its grandparent is a class declaration, this is a valid target;
               // return node.parent.body !== undefined
               //     && (node.parent.kind === 152 /* Constructor */
               //         || node.parent.kind === 151 /* MethodDeclaration */
               //         || node.parent.kind === 154 /* SetAccessor */)
   			//     && node.parent.parent.kind === 229 /* ClassDeclaration */;
   			
   			var parent = node.parent || (node.original && node.original.parent);
   			return parent && parent.body !== undefined &&
                     (parent.kind === 152
                        || parent.kind === 151
                        || parent.kind === 154) && parent.parent.kind === 229;
       }
       return false;
   }

Which comes from here, if you compile typescript:
shlomiassaf/TypeScript@7017fa2

@kclay
Copy link

kclay commented Dec 16, 2017

Getting this problem with

constructor(@Inject(APP_CONFIG) private config, private _http: HttpClient,
              @Inject(forwardRef(() => AttributesService))
              private _attributesService: AttributesService) 

Tried to do

export function serializeType<T>(object: T) {
  return function () { return object; }
}
   @Inject(forwardRef(serializeType(AttributesService)))
and
   @Inject(serializeType(AttributesService))

Both resulted in runtime errors when trying to run in dev mode.. With the normal forwardRef it runs in dev mode but fails with --aot or --prod switches.

@pleerock
Copy link
Contributor

We need to wait until angular team fix this issue. For now solution to avoid this problem is following:

    @Type(forwardRef(() => Person) as any)
    author: Person;

@kirillgroshkov
Copy link

I want to share my workaround that I put together after reading other advices here and there. It's patching an ng script from @angular/cli@1.6.4 (current version at the moment of writing). Because of that it prevents updating @angular/cli, so be prepared.

  1. Put a patched copy of ng somewhere in your repo. You can grab patched version from here:
    https://github.com/kirillgroshkov/angular-cli/blob/18f14d71bc5d73dba488f8fc1d08fd46d1d885f1/packages/%40angular/cli/bin/ng

Here's what changed, compared to the original file: https://github.com/kirillgroshkov/angular-cli/commit/18f14d71bc5d73dba488f8fc1d08fd46d1d885f1

  1. Add a postinstall script in your package.json that will run every time after you do npm install (or yarn install) and copy/overwrite ng from your location to node_modules/@angular/cli/bin/ng.
"postinstall": "echo 'patching @angular/cli' & cp ./other/ng ./node_modules/@angular/cli/bin"
  1. Run your build as normal, you should see console.log message "!!! using patched @angular/cli".
  2. Profit

@sebastian-zarzycki-apzumi
Copy link

sebastian-zarzycki-apzumi commented Feb 21, 2018

Is there a solution for @Transform using forwardRef (or similar)? I don't like that we have to patch it, but at least, the forwardRef solution is just adding things within the same line, as opposed to having to create other constructs. I could use similar solution for @Transform, if possible.

@andrea-spotsoftware
Copy link

andrea-spotsoftware commented Feb 22, 2018

@pleerock any workaround when we have:

@Type(forwardRef((options) => {
       // return (options.newObject as Generic<T>).entityType;
    }) as any)

?

Looks like forwardRefFn cannot have a parameter

PS: @jpduckwo your solution is not working

Metadata collected contains an error that will be reported at runtime: Lambda not supported.

@andrea-spotsoftware
Copy link

I resolved upgrading typescript to 2.7, throwing away forwardRef , and adding // @dynamic at the top of the class:

import { Expose, Type } from 'class-transformer';

import { LookupQueryDTO } from './lookup_dto';
import { LookupQueryInfo } from './lookup_query_info';

// @dynamic
export class LookupQueryComplete extends LookupQueryDTO {

	/** rootEntityName */
	@Expose()
	public rootEntityName: string;

	/** lookupQueryInfo */
	@Expose()
	@Type(() => LookupQueryInfo)
	public lookupQueryInfo: LookupQueryInfo;

}

@splincode
Copy link

Also not working in Angular

class Test {

@Transform(
      (value) => plainToClass(ApplicationData, JSON.parse(value)),
      { toClassOnly: true }
  )
  @Transform(
      (value) => JSON.stringify(classToPlain(value)),
      { toPlainOnly: true }
  )
  data: ApplicationData;

}

@sebastian-zarzycki-apzumi

Yeah, for now, you need to put just function reference there:

  @Transform(DateUtil.translateUtcDateTime)
  date: Date;

translateUtcDateTime is a static method in another class static translateUtcDateTime(value: string): Date, but you could have an exported function within the same object, I guess.

@splincode
Copy link

ts 2.5
angular 5.2.5
angular-cli 1.7.3

Not working

class TransferType {
  static stringify() {
    return (value) => JSON.stringify(classToPlain(value));
  }

  static parse() {
    return (value) => plainToClass(ApplicationData, JSON.parse(value));
  }
}

export class Application {

  @Transform(TransferType.parse(), { toClassOnly: true })
  @Transform(TransferType.stringify(), { toPlainOnly: true })
  data: ApplicationData = new ApplicationData();

}

@sebastian-zarzycki-apzumi

Pass the function reference, don't execute the function.

@splincode
Copy link

splincode commented Apr 5, 2018

Also problem remain

class TransferType {
  static stringify(value: string) {
    return JSON.stringify(classToPlain(value));
  }

  static parse(value: string) {
    return plainToClass(ApplicationData, JSON.parse(value));
  }
}

export class Application {

  @Transform(TransferType.parse, { toClassOnly: true })
  @Transform(TransferType.stringify, { toPlainOnly: true })
  data: ApplicationData;

}

export class ApplicationData {

  @Type(() => User)
  person: User;

  @Type(() => Travel)
  travel: Travel;

  @Type(() => Consumption)
  consumptions: Consumption[];

  @Type(() => Additional)
  additional: Additional;

}

Oh, I same problem )) @type(() => ...)
I forgot about them

@sebastian-zarzycki-apzumi

I don't think you can have two transforms over one field. Get one and extract the transform type from the parameter passed (second or third, don't remember), then react accordingly.

@NoNameProvided NoNameProvided added type: fix Issues describing a broken feature. flag: needs discussion Issues which needs discussion before implementation. labels Oct 26, 2018
@NoNameProvided
Copy link
Member

Sorry for the late reply guys! Does this need fixing on our side? It seems for me this is a bug in the Angular compiler.

@bastienlemaitre
Copy link

Up

@NoNameProvided NoNameProvided added status: invalid Issues with no action to take and removed flag: needs discussion Issues which needs discussion before implementation. labels Feb 14, 2021
@NoNameProvided NoNameProvided changed the title Builds fail with Angular 5 and Angular CLI when @Type is used fix: builds fail with Angular 5 and Angular CLI when @Type is used Feb 14, 2021
@NoNameProvided
Copy link
Member

This is an issue with Angular or project settings. Also, Angular 5 is not relevant anymore. If this happens in Angular 11 please open a new discussion.

Please note that by default newer Angulars doesn't include reflect-metadata what we use so make sure it's imported and emitDecoratorMetadata is set to true in your tsconfig.json.

@github-actions
Copy link

This issue has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 17, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
status: invalid Issues with no action to take type: fix Issues describing a broken feature.
Development

No branches or pull requests