Renderer and camera not defined in typescript class

Hi there!
I am using typescript to create a canvas with ThreeJS in a class.
The code is like this:

js/main.js:

import { PerspectiveCamera, Scene, WebGLRenderer } from "three";

class World {
    private windowWidth: number;
    private windowHeight: number;

    private renderer: WebGLRenderer;
    private camera: PerspectiveCamera;
    private scene: Scene;

    private viewAngle = 45;
    private aspectRatio: number;
    private cameraNear = 0.1;
    private cameraFar = 10000;

    constructor(container: string) {
        this.renderer = new WebGLRenderer({ 
            antialias: true
        });
        this.renderer.setSize(this.windowWidth, this.windowHeight);

        this.aspectRatio = this.windowWidth / this.windowHeight;            
        this.camera = new PerspectiveCamera(this.viewAngle, this.aspectRatio, this.cameraNear, this.cameraFar);
        this.camera.position.set(0, 0, 300);

        this.scene = new Scene();
        this.scene.add(this.camera);

        const html = document.querySelector(container);
        html?.appendChild(this.renderer.domElement);            

        function update() {
            this.renderer.render(this.scene, this.camera);
            requestAnimationFrame(update);
        }

        requestAnimationFrame(update);
    }
}

window.addEventListener('load',() => {
    new World('#container');
});

In index.html:

<body>
  <div id="container"></div>
  <script src="js/main.js"></script>
</body>

So at the bottom of the javascript I create an instance of the World class. On creation, the constructor is ran and it should create a canvas with a threeJS scene in it. I provide the id of the HTML Element upon creating the new World object, so it should know where to go.

If I run this I get errors like “Uncaught TypeError: Cannot read property ‘renderer’ of undefined”. This errors occurs inside of the update method. Has anybody else come across this error and how did they solve it? I don’t really understand how this can happen. It feels like there is some asynchronous action going on, because when I try to console.log “this.camera” right before the update function it does give me all the info of the camera object. If anyone could clarify how this works, I would be very grateful. :slight_smile:

When I run the code below, it does work, I do not get any errors: (with the same HTML)
Note the ‘const’ declarations of the variables.

class World {
    private windowWidth: number;
    private windowHeight: number;

    private viewAngle = 45;
    private aspectRatio: number;
    private cameraNear = 0.1;
    private cameraFar = 10000;

    constructor(container: string) {
        this.windowWidth = window.innerWidth;
        this.windowHeight = window.innerHeight;

        const renderer = new WebGLRenderer({ 
            antialias: true
        });
        renderer.setSize(this.windowWidth, this.windowHeight);
        this.aspectRatio = this.windowWidth / this.windowHeight;            

        const camera = new PerspectiveCamera( this.viewAngle, this.aspectRatio, this.cameraNear, this.cameraFar);
        camera.position.set(0, 0, 300);

        const scene = new Scene();
        scene.add(camera);

        const html = document.querySelector(container);
        html?.appendChild(renderer.domElement);

        function update() {
            renderer.render(scene, camera);
            requestAnimationFrame(update);
        }
        requestAnimationFrame(update);
    }
}

window.addEventListener('load',() => {
    new World('#container');
});

Try using
private renderer: THREE.WebGLRenderer;
private camera: THREE.PerspectiveCamera;
private scene: THREE.Scene;
etc

... new THREE.WebGLRenderer(...etc)
new THREE.PerspectiveCamera(....etc.)
new THREE.scene()
etc,

Or,
there are many typescript boilerplates that can show you how to get started.
There is sure to be at least one that uses a technique that you can agree with.

Sean-Bradley/Three.js-TypeScript-Boilerplate: Three.js TypeScript Boilerplate (github.com)

EDIT:
I see you’ve know included how you import three.
I don’t know. Its not a problem that I have.

Yea sorry, I forgot to include the import line.
Everything seems to work fine if I just use regular variables inside the constructor. But once I try to make the code more modular and use external methods and classes to create the renderer and the camera I get the errors mentioned above.
Could it be there is a bit of a delay when calling “new WebGLRenderer()”?

When I copy your code, my IDE shows problems with this.windowWidth and this.windowHeight.
So try declaring those.

Aight, thanks for that.
I realized that I started off a bit wrong, sorry about that.
I updated my example at the top and tried it again myself.
When I run the code in my starting post I get the error: Uncaught TypeError: Cannot read property ‘renderer’ of undefined

Do you have the same problem?

you need to share more code.
From what I can see, you also haven’t set the domElement of the renderer to any canvas.
And which line is reporting Cannot read property ‘renderer’ of undefined
Is it a piece of code outside the class. Your renderer is set private.
It’s hard to tell how you are instantiating it.

Thanks for your replies so far. I tried to update the code some more, and also provided a working example.
I do set the domElement to a canvas, I do this right before the update() method is declared.
I’m not going to be able to reply for a few days now. If it’s necessary I would like to elaborate more later, but I hope I provided a better example now.

I think you still have other problems,
but try updating your update function to be a const arrow function like this,

this is the other problem,


And I’m sure there is more.

Hi Sean,
Sorry for taking so long before getting back to you.
I figured out that the only issue was that I had not created an arrow function of the update method. That way it didn’t take the ‘this’ from the class but from the function itself. Of course ‘this.renderer’ or ‘this.scene’ is undefined in there that way!
Thanks a lot for your help! Really appreciated! :slight_smile:

1 Like