Typescript base class reference subclass











up vote
0
down vote

favorite












I am trying to create a tree-like structure with inheritance like the following:



base.ts:



export class BaseClass {
children: BaseClass = ;

get subclassChildren(): SubClass {
return this.children.filter((child): child is SubClass => child instanceof SubClass);
}
}


sub.ts:



import { BaseClass } from './base';
export class SubClass extends BaseClass {}


This wont work because the base class cannot find SubClass:




TSError: ⨯ Unable to compile TypeScript:
base.ts(4,26): error TS2304: Cannot find name 'SubClass'.
base.ts(5,49): error TS2304: Cannot find name 'SubClass'.
base.ts(5,78): error TS2304: Cannot find name 'SubClass'.



Not unexpected but if I try to import the subclass in base.ts it wont work either as there are circular references to each other:




TypeError: Object prototype may only be an Object or null: undefined



Is there a way to forward declare SubClass or some other way to get this code working?



EDIT:



tsconfig.json (generated by tsc --init):



{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"strict": true,
"esModuleInterop": true
}
}









share|improve this question




























    up vote
    0
    down vote

    favorite












    I am trying to create a tree-like structure with inheritance like the following:



    base.ts:



    export class BaseClass {
    children: BaseClass = ;

    get subclassChildren(): SubClass {
    return this.children.filter((child): child is SubClass => child instanceof SubClass);
    }
    }


    sub.ts:



    import { BaseClass } from './base';
    export class SubClass extends BaseClass {}


    This wont work because the base class cannot find SubClass:




    TSError: ⨯ Unable to compile TypeScript:
    base.ts(4,26): error TS2304: Cannot find name 'SubClass'.
    base.ts(5,49): error TS2304: Cannot find name 'SubClass'.
    base.ts(5,78): error TS2304: Cannot find name 'SubClass'.



    Not unexpected but if I try to import the subclass in base.ts it wont work either as there are circular references to each other:




    TypeError: Object prototype may only be an Object or null: undefined



    Is there a way to forward declare SubClass or some other way to get this code working?



    EDIT:



    tsconfig.json (generated by tsc --init):



    {
    "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "esModuleInterop": true
    }
    }









    share|improve this question


























      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I am trying to create a tree-like structure with inheritance like the following:



      base.ts:



      export class BaseClass {
      children: BaseClass = ;

      get subclassChildren(): SubClass {
      return this.children.filter((child): child is SubClass => child instanceof SubClass);
      }
      }


      sub.ts:



      import { BaseClass } from './base';
      export class SubClass extends BaseClass {}


      This wont work because the base class cannot find SubClass:




      TSError: ⨯ Unable to compile TypeScript:
      base.ts(4,26): error TS2304: Cannot find name 'SubClass'.
      base.ts(5,49): error TS2304: Cannot find name 'SubClass'.
      base.ts(5,78): error TS2304: Cannot find name 'SubClass'.



      Not unexpected but if I try to import the subclass in base.ts it wont work either as there are circular references to each other:




      TypeError: Object prototype may only be an Object or null: undefined



      Is there a way to forward declare SubClass or some other way to get this code working?



      EDIT:



      tsconfig.json (generated by tsc --init):



      {
      "compilerOptions": {
      "target": "es5",
      "module": "commonjs",
      "strict": true,
      "esModuleInterop": true
      }
      }









      share|improve this question















      I am trying to create a tree-like structure with inheritance like the following:



      base.ts:



      export class BaseClass {
      children: BaseClass = ;

      get subclassChildren(): SubClass {
      return this.children.filter((child): child is SubClass => child instanceof SubClass);
      }
      }


      sub.ts:



      import { BaseClass } from './base';
      export class SubClass extends BaseClass {}


      This wont work because the base class cannot find SubClass:




      TSError: ⨯ Unable to compile TypeScript:
      base.ts(4,26): error TS2304: Cannot find name 'SubClass'.
      base.ts(5,49): error TS2304: Cannot find name 'SubClass'.
      base.ts(5,78): error TS2304: Cannot find name 'SubClass'.



      Not unexpected but if I try to import the subclass in base.ts it wont work either as there are circular references to each other:




      TypeError: Object prototype may only be an Object or null: undefined



      Is there a way to forward declare SubClass or some other way to get this code working?



      EDIT:



      tsconfig.json (generated by tsc --init):



      {
      "compilerOptions": {
      "target": "es5",
      "module": "commonjs",
      "strict": true,
      "esModuleInterop": true
      }
      }






      typescript






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 20 at 13:53

























      asked Nov 20 at 13:22









      ext

      75821227




      75821227
























          2 Answers
          2






          active

          oldest

          votes

















          up vote
          0
          down vote













          Try this:



          base.ts:



              export class BaseClass {
          className = "base"
          children: BaseClass = ;
          get subclassChildren() {
          return this.children.filter((child) => { return child.className == "subClass" });
          }
          }


          sub.ts:



          import { BaseClass } from './base';
          export class SubClass extends BaseClass {
          className = "subClass"
          }





          share|improve this answer























          • The major issue here is that subclassChildren is not available on BaseClass any longer. And since children is still an array of BaseClass it would need a lot of casting.
            – ext
            Nov 20 at 13:39










          • And in this way?
            – javimovi
            Nov 20 at 13:49










          • This will filter out the subclasses but not cast them any longer, what I get is no longer a SubClass but a BaseClass.
            – ext
            Nov 20 at 13:58


















          up vote
          0
          down vote



          accepted










          Using module augmentation it is possible to add methods and properties to existing classes:



          base.ts:



          export class BaseClass {
          children: BaseClass = ;
          }


          sub.ts:



          import { BaseClass } from './base';

          export class SubClass extends BaseClass {
          foo(){
          console.log('foo');
          }
          }

          /* augment base class */
          declare module "./base" {
          interface BaseClass {
          subclassChildren: SubClass;
          bar(): void;
          }
          }

          /* implement getter */
          Object.defineProperty(BaseClass.prototype, 'subclassChildren', {
          get(){
          return this.children.filter((child: BaseClass): child is SubClass => child instanceof SubClass);
          },
          });

          /* implement method */
          BaseClass.prototype.bar = function bar(){
          console.log('bar');
          }


          When using it both base.ts and sub.ts has to be imported as only sub.ts contains the augmented class:



          import { BaseClass } from './base';
          import { SubClass } from './sub';

          const root = new BaseClass();
          root.children.push(new BaseClass());
          root.children.push(new SubClass());

          root.subclassChildren.map((child) => child.foo());
          root.bar();





          share|improve this answer





















            Your Answer






            StackExchange.ifUsing("editor", function () {
            StackExchange.using("externalEditor", function () {
            StackExchange.using("snippets", function () {
            StackExchange.snippets.init();
            });
            });
            }, "code-snippets");

            StackExchange.ready(function() {
            var channelOptions = {
            tags: "".split(" "),
            id: "1"
            };
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function() {
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled) {
            StackExchange.using("snippets", function() {
            createEditor();
            });
            }
            else {
            createEditor();
            }
            });

            function createEditor() {
            StackExchange.prepareEditor({
            heartbeatType: 'answer',
            convertImagesToLinks: true,
            noModals: true,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: 10,
            bindNavPrevention: true,
            postfix: "",
            imageUploader: {
            brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
            contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
            allowUrls: true
            },
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            });


            }
            });














            draft saved

            draft discarded


















            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53393965%2ftypescript-base-class-reference-subclass%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown

























            2 Answers
            2






            active

            oldest

            votes








            2 Answers
            2






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            0
            down vote













            Try this:



            base.ts:



                export class BaseClass {
            className = "base"
            children: BaseClass = ;
            get subclassChildren() {
            return this.children.filter((child) => { return child.className == "subClass" });
            }
            }


            sub.ts:



            import { BaseClass } from './base';
            export class SubClass extends BaseClass {
            className = "subClass"
            }





            share|improve this answer























            • The major issue here is that subclassChildren is not available on BaseClass any longer. And since children is still an array of BaseClass it would need a lot of casting.
              – ext
              Nov 20 at 13:39










            • And in this way?
              – javimovi
              Nov 20 at 13:49










            • This will filter out the subclasses but not cast them any longer, what I get is no longer a SubClass but a BaseClass.
              – ext
              Nov 20 at 13:58















            up vote
            0
            down vote













            Try this:



            base.ts:



                export class BaseClass {
            className = "base"
            children: BaseClass = ;
            get subclassChildren() {
            return this.children.filter((child) => { return child.className == "subClass" });
            }
            }


            sub.ts:



            import { BaseClass } from './base';
            export class SubClass extends BaseClass {
            className = "subClass"
            }





            share|improve this answer























            • The major issue here is that subclassChildren is not available on BaseClass any longer. And since children is still an array of BaseClass it would need a lot of casting.
              – ext
              Nov 20 at 13:39










            • And in this way?
              – javimovi
              Nov 20 at 13:49










            • This will filter out the subclasses but not cast them any longer, what I get is no longer a SubClass but a BaseClass.
              – ext
              Nov 20 at 13:58













            up vote
            0
            down vote










            up vote
            0
            down vote









            Try this:



            base.ts:



                export class BaseClass {
            className = "base"
            children: BaseClass = ;
            get subclassChildren() {
            return this.children.filter((child) => { return child.className == "subClass" });
            }
            }


            sub.ts:



            import { BaseClass } from './base';
            export class SubClass extends BaseClass {
            className = "subClass"
            }





            share|improve this answer














            Try this:



            base.ts:



                export class BaseClass {
            className = "base"
            children: BaseClass = ;
            get subclassChildren() {
            return this.children.filter((child) => { return child.className == "subClass" });
            }
            }


            sub.ts:



            import { BaseClass } from './base';
            export class SubClass extends BaseClass {
            className = "subClass"
            }






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 20 at 13:54

























            answered Nov 20 at 13:35









            javimovi

            318110




            318110












            • The major issue here is that subclassChildren is not available on BaseClass any longer. And since children is still an array of BaseClass it would need a lot of casting.
              – ext
              Nov 20 at 13:39










            • And in this way?
              – javimovi
              Nov 20 at 13:49










            • This will filter out the subclasses but not cast them any longer, what I get is no longer a SubClass but a BaseClass.
              – ext
              Nov 20 at 13:58


















            • The major issue here is that subclassChildren is not available on BaseClass any longer. And since children is still an array of BaseClass it would need a lot of casting.
              – ext
              Nov 20 at 13:39










            • And in this way?
              – javimovi
              Nov 20 at 13:49










            • This will filter out the subclasses but not cast them any longer, what I get is no longer a SubClass but a BaseClass.
              – ext
              Nov 20 at 13:58
















            The major issue here is that subclassChildren is not available on BaseClass any longer. And since children is still an array of BaseClass it would need a lot of casting.
            – ext
            Nov 20 at 13:39




            The major issue here is that subclassChildren is not available on BaseClass any longer. And since children is still an array of BaseClass it would need a lot of casting.
            – ext
            Nov 20 at 13:39












            And in this way?
            – javimovi
            Nov 20 at 13:49




            And in this way?
            – javimovi
            Nov 20 at 13:49












            This will filter out the subclasses but not cast them any longer, what I get is no longer a SubClass but a BaseClass.
            – ext
            Nov 20 at 13:58




            This will filter out the subclasses but not cast them any longer, what I get is no longer a SubClass but a BaseClass.
            – ext
            Nov 20 at 13:58












            up vote
            0
            down vote



            accepted










            Using module augmentation it is possible to add methods and properties to existing classes:



            base.ts:



            export class BaseClass {
            children: BaseClass = ;
            }


            sub.ts:



            import { BaseClass } from './base';

            export class SubClass extends BaseClass {
            foo(){
            console.log('foo');
            }
            }

            /* augment base class */
            declare module "./base" {
            interface BaseClass {
            subclassChildren: SubClass;
            bar(): void;
            }
            }

            /* implement getter */
            Object.defineProperty(BaseClass.prototype, 'subclassChildren', {
            get(){
            return this.children.filter((child: BaseClass): child is SubClass => child instanceof SubClass);
            },
            });

            /* implement method */
            BaseClass.prototype.bar = function bar(){
            console.log('bar');
            }


            When using it both base.ts and sub.ts has to be imported as only sub.ts contains the augmented class:



            import { BaseClass } from './base';
            import { SubClass } from './sub';

            const root = new BaseClass();
            root.children.push(new BaseClass());
            root.children.push(new SubClass());

            root.subclassChildren.map((child) => child.foo());
            root.bar();





            share|improve this answer

























              up vote
              0
              down vote



              accepted










              Using module augmentation it is possible to add methods and properties to existing classes:



              base.ts:



              export class BaseClass {
              children: BaseClass = ;
              }


              sub.ts:



              import { BaseClass } from './base';

              export class SubClass extends BaseClass {
              foo(){
              console.log('foo');
              }
              }

              /* augment base class */
              declare module "./base" {
              interface BaseClass {
              subclassChildren: SubClass;
              bar(): void;
              }
              }

              /* implement getter */
              Object.defineProperty(BaseClass.prototype, 'subclassChildren', {
              get(){
              return this.children.filter((child: BaseClass): child is SubClass => child instanceof SubClass);
              },
              });

              /* implement method */
              BaseClass.prototype.bar = function bar(){
              console.log('bar');
              }


              When using it both base.ts and sub.ts has to be imported as only sub.ts contains the augmented class:



              import { BaseClass } from './base';
              import { SubClass } from './sub';

              const root = new BaseClass();
              root.children.push(new BaseClass());
              root.children.push(new SubClass());

              root.subclassChildren.map((child) => child.foo());
              root.bar();





              share|improve this answer























                up vote
                0
                down vote



                accepted







                up vote
                0
                down vote



                accepted






                Using module augmentation it is possible to add methods and properties to existing classes:



                base.ts:



                export class BaseClass {
                children: BaseClass = ;
                }


                sub.ts:



                import { BaseClass } from './base';

                export class SubClass extends BaseClass {
                foo(){
                console.log('foo');
                }
                }

                /* augment base class */
                declare module "./base" {
                interface BaseClass {
                subclassChildren: SubClass;
                bar(): void;
                }
                }

                /* implement getter */
                Object.defineProperty(BaseClass.prototype, 'subclassChildren', {
                get(){
                return this.children.filter((child: BaseClass): child is SubClass => child instanceof SubClass);
                },
                });

                /* implement method */
                BaseClass.prototype.bar = function bar(){
                console.log('bar');
                }


                When using it both base.ts and sub.ts has to be imported as only sub.ts contains the augmented class:



                import { BaseClass } from './base';
                import { SubClass } from './sub';

                const root = new BaseClass();
                root.children.push(new BaseClass());
                root.children.push(new SubClass());

                root.subclassChildren.map((child) => child.foo());
                root.bar();





                share|improve this answer












                Using module augmentation it is possible to add methods and properties to existing classes:



                base.ts:



                export class BaseClass {
                children: BaseClass = ;
                }


                sub.ts:



                import { BaseClass } from './base';

                export class SubClass extends BaseClass {
                foo(){
                console.log('foo');
                }
                }

                /* augment base class */
                declare module "./base" {
                interface BaseClass {
                subclassChildren: SubClass;
                bar(): void;
                }
                }

                /* implement getter */
                Object.defineProperty(BaseClass.prototype, 'subclassChildren', {
                get(){
                return this.children.filter((child: BaseClass): child is SubClass => child instanceof SubClass);
                },
                });

                /* implement method */
                BaseClass.prototype.bar = function bar(){
                console.log('bar');
                }


                When using it both base.ts and sub.ts has to be imported as only sub.ts contains the augmented class:



                import { BaseClass } from './base';
                import { SubClass } from './sub';

                const root = new BaseClass();
                root.children.push(new BaseClass());
                root.children.push(new SubClass());

                root.subclassChildren.map((child) => child.foo());
                root.bar();






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Nov 23 at 16:33









                ext

                75821227




                75821227






























                    draft saved

                    draft discarded




















































                    Thanks for contributing an answer to Stack Overflow!


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.





                    Some of your past answers have not been well-received, and you're in danger of being blocked from answering.


                    Please pay close attention to the following guidance:


                    • Please be sure to answer the question. Provide details and share your research!

                    But avoid



                    • Asking for help, clarification, or responding to other answers.

                    • Making statements based on opinion; back them up with references or personal experience.


                    To learn more, see our tips on writing great answers.




                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function () {
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53393965%2ftypescript-base-class-reference-subclass%23new-answer', 'question_page');
                    }
                    );

                    Post as a guest















                    Required, but never shown





















































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown

































                    Required, but never shown














                    Required, but never shown












                    Required, but never shown







                    Required, but never shown







                    Popular posts from this blog

                    Feedback on college project

                    Futebolista

                    Albești (Vaslui)