Skip to content

Transforming class member with decorators throws #17384

Description

TypeScript Version: 2.4.0

Code

Can't use something that runs from "tsc" since it does not support transformers

In a PropertyDeclaration visitor

return ts.updateProperty(
          node,
          node.decorators[0], // assume we have 2 or more decorators...
          node.modifiers,
          node.name,
          node.type,
          node.initializer
        );

Expected behavior:
Should compile.

Actual behavior:
Exception is thrown TypeError: Cannot read property 'kind' of undefined

The exception is throw from here

    export function nodeCanBeDecorated(node: Node): boolean {
        switch (node.kind) {
            case SyntaxKind.ClassDeclaration:
                // classes are valid targets
                return true;

            case SyntaxKind.PropertyDeclaration:
                // property declarations are valid if their parent is a class declaration.
                return node.parent.kind === SyntaxKind.ClassDeclaration;

            case SyntaxKind.GetAccessor:
            case SyntaxKind.SetAccessor:
            case SyntaxKind.MethodDeclaration:
                // if this method has a body and its parent is a class declaration, this is a valid target.
                return (<FunctionLikeDeclaration>node).body !== undefined
                    && node.parent.kind === SyntaxKind.ClassDeclaration;

            case SyntaxKind.Parameter:
                // if the parameter's parent has a body and its grandparent is a class declaration, this is a valid target;
                return (<FunctionLikeDeclaration>node.parent).body !== undefined
                    && (node.parent.kind === SyntaxKind.Constructor
                        || node.parent.kind === SyntaxKind.MethodDeclaration
                        || node.parent.kind === SyntaxKind.SetAccessor)
                    && node.parent.parent.kind === SyntaxKind.ClassDeclaration;
        }

        return false;
    }

Trying to reach node.parent.kind while node.parent is undefined, which is common to all "synthesized" nodes, i.e. transforming nodes.

This is true to all other members... Parameter, MethodDeclaration, GetAccessor and SetAccessor

Activity

  1. shlomiassaf commented on Jul 25, 2017

    @shlomiassaf
    Author

    I think this PR should fix the problem...

    Testing it now.

  2. added a commit that references this issue on Jul 25, 2017
    5720244
  3. tbosch commented on Aug 3, 2017

    @tbosch

    This bug also affects Angular / Tsickle as we are now using transformers. Our workaround (see transformer_util.ts):

    • setting the parent for synthetic nodes
    • not using ts.updateSourceFileNode but instead doing this:
      const sf = getMutableClone(sf);
      sf.statements = statements;
      return sf;
      

    /cc Martin Probst (@mprobst) Evan Martin (@evmar) Alex Eagle (@alexeagle)

  4. filipesilva commented on Sep 15, 2017

    @filipesilva
    Contributor

    Tobias Bosch (@tbosch) the related issue #17551 is fixed in 2.5.0 via #18051. Perhaps the workaround in Angular can go away when typescript is detected to be that version of greater.

    import { satisfies } from 'semver';
    const visitEachChild = satisfies(ts.version, '^2.5.0')
      ? ts.visitEachChild
      : visitEachChildWorkaround;
    

    This issue should be closed since I think #18051 fixes both.

  5. shlomiassaf commented on Nov 6, 2017

    @shlomiassaf
    Author

    Filipe Silva (@filipesilva) from what I see #18051 did not solve the issue, or at least did not solve it completely.

    See angular/angular#20216

    cc Ron Buckton (@rbuckton)

  6. niveo commented on Nov 28, 2017

    @niveo

    typestack/class-transformer#108

    Revin Roman (@rmrevin)

    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;
    
    }
    
  7. added
    BugA bug in TypeScript
    and removed
    Needs InvestigationThis issue needs a team member to investigate its status.
    on Nov 28, 2017
  8. niveo commented on Dec 15, 2017

    @niveo

    angular/angular-cli#8434

    George Mavritsakis (@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

  9. kirillgroshkov commented on Jan 13, 2018

    @kirillgroshkov

    Waiting for the fix... It affects our project to upgrade to Angular5..

  10. kirillgroshkov commented on Jan 13, 2018

    @kirillgroshkov

    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
  11. togbyte commented on Jan 31, 2018

    @togbyte

    I have the same issue. Is this a problem with Angular, Typescript, or Angular CLI?

  12. weswigham commented on Feb 1, 2018

    @weswigham
    Member

    This is fixed in our just-released 2.7 build; so you'd have to wait for a new version of the angular CLI that makes use of it, or manually patch your local outdated copy like those above did (not recommended).

  13. filipesilva commented on Feb 1, 2018

    @filipesilva
    Contributor

    Wesley Wigham (@weswigham) awesome, thanks for the update!

  14. locked and limited conversation to collaborators on Jul 3, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

BugA bug in TypeScriptDomain: APIRelates to the public API for TypeScriptFixedA PR has been merged for this issue

Type

No type

Projects

No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions