Namespace is undefined after compile

1.8k Views Asked by At

I am writing a little game engine in typescript, and when I compile it to javascript, I get an error when running the javascript. It compiles without error too.

My main entry file (main.ts) starts with these two lines:

require('./core/Obj');
require('./core/Component');

It builds out fine but when I run it, the second require has some issues and gives this error:

Uncaught TypeError: Class extends value undefined is not a function or null

core/Obj.ts

namespace GameEngine {
    export class Obj {
        // Some functions/methods
    }
}

core/Component.ts

namespace GameEngine {
    export class Component extends Obj {
    }
}

Then once it is compiled, it looks something like this:

(function (exports, require, module, __filename, __dirname, process, global) { (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[
    function(require,module,exports){
        var GameEngine;
        (function (GameEngine) {
            class Component extends GameEngine.Obj { // Error is here
            }
            GameEngine.Component = Component;
        })(GameEngine || (GameEngine = {}));
    },{}],
    5:[function(require,module,exports){
        var GameEngine;
        (function (GameEngine) {
            class Obj {
            }
            GameEngine.Obj = Obj;
        })(GameEngine || (GameEngine = {}));
    },{}]
});

Here is the gulp task that I am running:

gulp.task('compile-engine', function () {
    return browserify()
        .add('./GameEngine/main.ts')
        .plugin(tsify, {})
        .bundle()
        .on('error', function (error) { throw error; })
        .pipe(source('gameEngine.js'))
        .pipe(buffer())
        .pipe(gulp.dest('build/'));
});
1

There are 1 best solutions below

1
On

Each module has its own GameEngine namespace - as modules don't pollute the global scope. (In the compiled bundle in your question, you can see that they are separate.) There is an answer here that explains namespaces and modules.

In using tsify, you're using (external) modules. Things can be made simpler if you do away with the namespacing. The TypeScript Handbook has this to say about using namespaces with modules:

A key feature of modules in TypeScript is that two different modules will never contribute names to the same scope. Because the consumer of a module decides what name to assign it, there's no need to proactively wrap up the exported symbols in a namespace.

You could change the exports and imports to something like this:

core/Obj.ts

export class Obj {
    // Some functions/methods
}

core/Component.ts

import { Obj } from "./Obj";
export class Component extends Obj {
}

main.ts

import { Component } from "./core/Component";
// Do something with Component