0
votes

I am trying to work exclusively in typescript for the front end of an ASP.Net MVC application. This is working right now without modules and the dependency tracking is getting onerous. So it is time to bring in RequireJS and use Typescript's support of AMD.

I have read a lot about this and I think I am very close. However, I am running into a problem with the import statement of typescript saying that it can't find the shim modules that are defined in the requireJS configuration. So if typescript would just pass the name of the module through to the require function in the JS code, everything would work great. But it doesn't, it just throws an error. So the question is how am I supposed to write the import statement for these JS shims?

Here is an example: app.ts

import g = require("Api/greeter");
import $ = require("jquery");
import respond = require("respond");

var greeter = new g.Greeter("#content");
greeter.start();

Lets assume this is the main TS for a page and greeter is the view model for that page. But I know that I need jquery and bootstrap on the page. I have this setup for my requireJS config:

///

requirejs.config({
    baseUrl: 'Scripts',
    paths: {
        "jquery": "libs/jquery-3.1.1",
        "bootstrap": "libs/bootstrap.min",
        "respond" : "libs/respond"
    },
    shim: {
        "bootstrap": { deps: ["jquery"] },
        "respond": { deps: ["bootstrap"] }
    }
});

require(['App/app']);

Notice I have respond requiring bootstrap and bootstrap requiring jQuery. So having app.ts require respond should (and does) pull in respond, bootstrap and jQuery.

I know I have a redundant require("jQuery") in app.ts. That is for illustrative purposes only. Ie, that line works fine - TS recognizes jQuery as a valid module name and puts it into the resulting compiled JS file. But TS doesn't recognize "respond" as a module name and I get a compile error:

Cannot find module 'respond'.

I have my files arranged like this:

Scripts
->Api
    --> Greeter.ts
-> App
    --> App.ts
-> libs
    --> jQuery-3.1.1.js
    --> bootstrap.js
    --> respond.js

I thought I was doing well when jQuery worked but how do I get respond or any other pure JS library I have to pull in to work? From what I can tell in the TS docs, the argument to require() is supposed to be a valid path to a JS file because that's how the compiler is going to get the type information. But if that is the case, why does jQuery work the way I have it defined? It is no different than respond.js.

Thanks Greg

1
I may have just answered my own question. I think the important bit of information here is that I installed jQuery.d.ts and require.d.ts but I did not get a .d.ts file for respond. I figured this out as I tried to push forward to include knockout. VS was giving me the same error with knockout as it was with respond. Then I installed knockout.d.ts and all of a sudden my error went away.Greg Veres

1 Answers

0
votes

I ran across this part of the typescript documentation that deals with using requireJS to load knockout.

In it, they briefly tell you to load the type definition file for knockout:

We’ll also grab declaration files for Knockout to describe the library’s shape for TypeScript.

npm install --save @types/knockout

this turns out to be the magic that is needed for the typescript compiler to stop complaining about the unknown package.

In the example I listed above, I had installed the type definition file for jQuery, hence the compiler didn't complain about jQuery. But I didn't have a type definition file for respond.js. Since there was no type definition file for respond.js, the complier then went looking for respond.js, and it assumes the argument to the require statement is a path it can follow to find the file to import. I believe that require assumes the file is a typescript file and looks for a .ts because I couldn't get the require statement to find the respond.js file either.

The bottom line is that import works in two ways when configured to use AMD (I can't speak to the other configurations yet).

  1. it uses the name of the module to match a type definition file that it knows about. If it matches a type definition file, it assumes that the name of the module is just that argument name and it passes it through to the require command in the generated javascript. At this point you are responsible to have built the infrastructure to load that module (i.e., your html page loads the file directly, or more likely, your requireJS configuration knows how to load that module)

    I.e. import $ = require("jQuery"); // loads via requireJS config

  2. it uses the name to find a source file in your project. The argument specified is a relative path to your source file.

    I.e. import g = require("Components/greeter"); // loads the greeter.ts module from the Components directory of your project. This should be set up to load via requireJS as well.

I hope this helps somebody else in the future.