visual studio typescript “Uncaught ReferenceError:

2019-01-15 09:49发布

问题:

I am learning typeScript with visual studio and trying to do a simple class export. I have seen this problem many times, but none of the solutions helped me. what am I doing wrong ?

  • I have changed module system from CommonJs to system
  • I have installed npm systemJs
  • tried instead of "import" to write "/// ...reference path.... / "

still the same error "Uncaught ReferenceError: exports is not defined at..."

import { Address } from "./address";

class Customer {
  protected name: string = "";
  public addressObj: Address = new Address();
  private _CustomerName: string = "";
  public set CustomerName(value: string) {
    if (value.length == 0) {
      throw "Customer name is requaierd"
    }
    this._CustomerName = value;
  }
  public get CustomerName(): string {
    return this._CustomerName;
  }
}
export class Address {
        public street1: string = "";
    }
<!doctype html>
<html>

<head>
  <title></title>
  <meta charset="utf-8" />
</head>

<body>
  <script src="address.js"></script>
  <script src="Customer.js"></script>
  <script>
    try {
      cust = new Customer();
      cust.CustomerName = "doron";
      cust.addressObj.street1 = "test"
    } catch (ex) {
      alert(ex);
    }
  </script>
</body>

</html>

what else am I not doing ?!?!

回答1:

I've just solved this. Or rather I found a blog post that does https://blorkfish.wordpress.com/2012/10/23/typescript-organizing-your-code-with-amd-modules-and-require-js/. To follow the proper SO guidelines I will reproduce it here.

Why you get 'exports is undefined' is due to Visual Studio transpiling to use commonjs modules. I looked at this for days trying different things and the message seemed to be that commonjs is the default and should "just work" (TM). But doesn't. I don't know what is missing - perhaps VS needs some include. I couldn't work out what.

The transpiled class using commonjs will include lines like this at the top and bottom of the .js file:

Object.defineProperty(exports, "__esModule", { value: true });
...
exports.SpeciesClass = SpeciesClass;

This is your error.

The solution that worked for me was to use requirejs. It is an implementation of AMD (http://requirejs.org/docs/whyamd.html). It still uses exports but wraps it in a define:

define(["require", "exports"], function (require, exports) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    ...
    exports.SpeciesClass = SpeciesClass;

What follows is pretty-much the blog post https://blorkfish.wordpress.com/2012/10/23/typescript-organizing-your-code-with-amd-modules-and-require-js/. With some modifications for the most recent version of Typescript. Unfortunately where I'm working I don't have access to github (or anything like that) so I can only paste my files in here.

I also had to allow for some issues with Visual Studio. I found that despite configuring the project.csproj's <TypescriptModuleKind> to be AMD, it seemed to always default to commonjs. So I transpile manually and hope to find a solution to stop VS defaulting.

I created a tsconfig.json file (tsc --init) and set the module to amd. I added a "Files": ["*.ts"].

{
  "compilerOptions": {
    /* Basic Options */
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', or 'ESNEXT'. */
    "module": "amd",                     /* Specify module code generation: 'none', commonjs

    /* ... */

    /* Strict Type-Checking Options */
    "strict": true                            /* Enable all strict type-checking options. */
  },
  "Files" : ["*.ts"]
}

Commented out lines (with defaults) removed.

After starting the server, Visual Studio would transpile the files (using commonjs module format). Requiring me to run tsc to force the files to transpile to use the amd module format. And it worked (no errors seen in the developer console).

First the files layout (from blogpost). What I have is the same except i've called my file index.html as default.htm reminds me of the bad ole days. You can get require.js from http://requirejs.org/. And require.d.ts from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/requirejs (save the index.d.ts as require.d.ts).

Greeter.ts

export class Greeter {
    element: HTMLElement;
    span: HTMLElement;
    timerToken: number;

    constructor(element: HTMLElement) {
        this.element = element;
        this.element.innerText += "The time is: ";
        this.span = document.createElement('span');
        this.element.appendChild(this.span);
        this.span.innerText = new Date().toUTCString();
    }

    start() {
        this.timerToken = setInterval(() => this.span.innerText = new Date().toUTCString(), 500);
    }

    stop() {
        clearTimeout(this.timerToken);
    }

}

AppConfig.ts

import { AppMain } from "./AppMain"

require(['AppMain'], 
    (main: any) => {
        var appMain = new AppMain();
        appMain.run();
    }
);

AppMain.ts

import { Greeter } from "./classes/Greeter"

export class AppMain {
    public run() {
        // code from window.onload
        var dummyEl: HTMLElement = document.createElement('span');
        var theEl: HTMLElement | null = document.getElementById('content');;
        var el: HTMLElement = theEl !== null ? theEl : dummyEl;
        var greeter: Greeter = new Greeter(el);
        greeter.start();
    }
};

Or use:

        var theEl: HTMLElement = document.getElementById('content');
        var greeter: Greeter = new Greeter(theEl);

And just realise that what is called an 'error' when you transpile is just a warning!:

app/AppMain.ts(7,13): error TS2322: Type 'HTMLElement | null' is not assignable to type 'HTMLElement'.
    Type 'null' is not assignable to type 'HTMLElement'.

app.ts

No longer used

index.html

<html lang="en">
    <head>
        <meta charset="utf-8" />
        <title>TypeScript HTML App</title>
        <link rel="stylesheet" href="app.css" type="text/css" />
        <!--
            <script type="text/javascript" src="app/classes/Greeter.js"></script>
            <script src="app.js"></script>
        -->
        <script data-main="app/AppConfig" type="text/javascript" src="lib/require.js"></script>
    </head>
    <body>
        <h1>TypeScript HTML App</h1>

        <div id="content"></div>
    </body>
</html>


回答2:

CommonJs isn't needed. Wrap all typescript in a common namespace and then export other namespaces, class, etc. Does offer intellisense:

namespace GlobalNamespace {
     export class MyClass1 {
         prop1:string;
     }
}

namespace GlobalNamespace {
     export class MyClass2 {
          prop2:string;
     }
}

Divide into namespace units:
namespace GlobalNamespace {
     export namespace SubNamespace1 {
        export class SubClass1 {
             myClass1: MyClass1;
        }
     }
}

namespace GlobalNamespace {
     export namespace SubNamespace2 {
        export class SubClass2 {
             subClass1:SubNamespace1.SubClass1;
        }
     }
}

Instantiate SubClass2

var subClass2 = new GlobalNamespace.SubNamespace2.SubClass2();