skip to Main Content

I’m new to TS, and I have a question about initializing classes
Here example of parsing object

const myObj = {
    "square": 100,
    "trees": [
        {
            "height": 100,
            "needles": 100500
        },
        {
            "height": 50,
            "apples": 20
        }
    ]
};


class Forest {
    constructor(
        public square: number,
        public trees: (Pine | AppleTree)[]
    ) {}
}

class Tree {
    constructor(
        public height: number,
    ) {}
}

class Pine extends Tree {
    constructor(
        public height: number,
        public needles: number,
    ) {
        super(height);
    }
}

class AppleTree extends Tree {
    constructor(
        public height: number,
        public apples: number,
    ) {
        super(height);
    }

    public getApples() {
        console.log(this.apples);
    }
}


export function initMyClass() {
    const forest: Forest = myObj;
}

But here is a compilation error – myObject Type is not assignable to type ‘Forest’. How can I parse object to that class?
And how to determine what subclass of Tree should be used to parse particular object in array

I tried interfaces, but, maybe not in a right way

2

Answers


  1. Chosen as BEST ANSWER

    I solved my problem using lib https://www.npmjs.com/package/class-transformer The code is below:

    enum TreeTypes {
        PINE = "pine",
        APPLETREE = "appleTree",
    }
    
    abstract class Tree {
        @Expose() public height: number;
        @Expose() public type: string;
    }
    
    class Pine extends Tree {
        @Expose() public height: number;
        @Expose() public needles: number;
    }
    
    class AppleTree extends Tree {
        @Expose() public height: number;
        @Expose() public apples: number;
        
        public getApples() {
            console.log(this.apples);
        }
    }
    
    class Forest {
        @Expose() square: number;
        
        @Type(() => Tree, {
            keepDiscriminatorProperty: true,
            discriminator: {
                property: 'type',
                    subTypes: [
                    { value: AppleTree, name: TreeTypes.APPLETREE },
                    { value: Pine, name: TreeTypes.PINE },
                ],
            },
        })
        @Expose()
        trees: (Pine | AppleTree)[];
    
        @Expose() 
        getSquare() {
            console.log(this.square);
        }
    }
    
    
    
    export function initMyClass() {
        const forest: Forest = plainToClass(Forest, myObj, { excludeExtraneousValues: true, enableCircularCheck: true, exposeDefaultValues: true });
        console.log(forest);
        
    }
    

  2. The problem is because AppleTree is not a plain object but rather it contains a public instance method called getApples. In JavaScript, you need to instantiate a class for you to get the methods defined in the class.

    As the original myObj doesn’t contain the getApples, TypeScript noticed that it doesn’t match the AppleTree class that you defined, which is why TypeScript complained about the error.

    class Forest {
      constructor(public square: number, public trees: (Pine | AppleTree)[]) {}
    }
    
    class Tree {
      constructor(public height: number) {}
    }
    
    class Pine extends Tree {
      constructor(public height: number, public needles: number) {
        super(height);
      }
    }
    
    class AppleTree extends Tree {
      constructor(public height: number, public apples: number) {
        super(height);
      }
    
      public getApples() {
        console.log(this.apples);
      }
    }
    
    const myObj = {
      square: 100,
      trees: [
        {
          height: 100,
          needles: 100500
        },
        new AppleTree(50, 20)
      ]
    };
    
    export function initMyClass() {
      const forest: Forest = myObj;
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search