I am having trouble finding good information about using TypeScript with RequireJS (I am a big fanboy of AMD/RequireJS) - I have this question on SO:
http://stackoverflow.com/questions/41761172/declaring-requirejs-dependencies-with-typescript
installing @types/redux helps but it doesn't solve the problem entirely. My primary concern is twofold:
(1) how do we tell TypeScript about the globals "require"/"requirejs" that exist in the main requirejs load script? As you can see in the images, Webstorm highlights them as red because they are not recognized by TS. (If you look at the image below, I am not sure why requirejs is red, the first require is recognized, but the second require gets a typing error saying "invalid number of arguments, 1 expected".)
(2) how do we tell TypeScript about the dependencies that are loaded as paths in the requirejs.config({paths:{}}) object? For example, how do I tell TS that 'immutable' or 'rxjs' is loaded as a network dependency and is not loaded until runtime?
e.g.:

please advise, thanks very much! once I figure this out, I will publish an article on it, to share the knowledge
(1) how do we tell TypeScript about the globals "require"/"requirejs" that exist in the main requirejs load script? As you can see in the images, Webstorm highlights them as red because they are not recognized by TS. (If you look at the image below, I am not sure why requirejs is red, the first require is recognized, but the second require gets a typing error saying "invalid number of arguments, 1 expected".)
Use @types/requirejs, this should get you the global as well as the "module" module.
(2) how do we tell TypeScript about the dependencies that are loaded as paths in the requirejs.config({paths:{}}) object? For example, how do I tell TS that 'immutable' or 'rxjs' is loaded as a network dependency and is not loaded until runtime?
Set paths property in your tsconfig.json to reflect these in your requirejs config file. you can find more information about this in www.typescriptlang.org/docs/handbook/module-resolution.html#path-mapping
thanks so much, let me try this
thanks, I looked at the module-resolution #path-mapping section
so I tried this (you can see the paths are CDN urls, they are not paths to node_modules, although I suppose I could add those if necessary to get things to compile)
{
"compilerOptions": {
"baseUrl": "public",
"paths": {
"rxjs": [
"//cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.1/Rx"
],
"async": [
"//cdnjs.cloudflare.com/ajax/libs/async/2.1.4/async"
],
"react-dom": [
"//cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom"
],
"react": [
"//cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-with-addons"
],
"socketio": [
"//cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.2/socket.io"
],
"@hot-reload-handler": [
"js/hot-reload-handler"
],
"@hot-reloader": [
"js/hot-reloader"
],
"tslib": [
"vendor/tslib"
],
"immutable": [
"//cdnjs.cloudflare.com/ajax/libs/immutable/3.8.1/immutable"
],
"react-redux": [
"//cdnjs.cloudflare.com/ajax/libs/react-redux/4.4.5/react-redux"
],
"redux": [
"//cdnjs.cloudflare.com/ajax/libs/redux/3.5.2/redux"
]
},
"types": [
"node",
"lodash",
"react",
"react-dom",
"redux",
"react-redux",
"async",
"requirejs" // <<< added this, and npm installed @types/requirejs
],
"typeRoots": [
"node_modules/@types"
],
"compileOnSave": true,
"target": "es5",
"module": "amd",
"noImplicitAny": false,
"removeComments": true,
"preserveConstEnums": true,
"allowJs": true,
"allowUnreachableCode": true,
"moduleResolution": "classic",
"lib": [
"es2015",
"dom"
]
},
"include": [
"./public/**/*.ts",
"./public/**/*.tsx"
]
}
If I use the above tsconfig.json
I still get:

and

any idea what might be up? thanks for your support
if the pictures are too hard to read please let me know
I assume that something else should go in the paths arrays, besides the URLs pointing to CDN? The link you gave me didn't see to make it clear what to put in there.
I think this might answer my question:
it says:
De-referencing Globals
In order to keep the Typescript compiler happy and not end up with compilation errors, or have a boat load of type imports you may only use once or twice, it's sometimes easier to simply manage the external libraries yourself. Import it using a regular script tag, or packaged as part of a separate vendor bundle and then simply referenced in the main page.
So rather than using import to pull in the library, we can just import using <script> tag as in the past:
Then in any Typescript class/component where you want to use these libraries explicitly dereference each of the library globals by explicitly using declare and casting them to any:
declare var $:any;
declare var toastr: any;
might that solve my problem? Do I really have to put those declarations in all my files which reference
your paths section is not correct. the compiler will not look up your CDN files. I think I was not clear. your requirejs config stays the way it is, the compiler is not going to write that for you. the compiler will try to find your modules in node_modules\@types, e.g. import ... from "react" will look it up under node_modules\@types\react. if your modules are in another place, use path mapping to match that.
A few things from your config file:
node for "module-resolution"?allowJs? i do not see any .js files?compileOnSave is in the worng place, it is not under compilerOption, it is a sipplingtypeRoots. the value you set is already the default..here is what i think you need:
"moduleResolution": "node"@types packages for missing depenedencies, e.g. immutable@hot-reloader, and @hot-reload-handler come from, but either you have .d.ts for them, then add a path mapping from "@hot-reload" : "declarationFiles\hot-reload\index.d.ts" or just remove it, if hte compiler can not find it, it will get the type any. here is what i think your config file should look like:
{
"compilerOptions": {
"baseUrl": "public",
"paths": {
"@hot-reload-handler": [ "<path to .d.ts for js/hot-reload-handler>"],
"@hot-reloader": ["<path to .d.ts for js/hot-reloader>"]
},
"types": [
"node",
"lodash",
"react",
"react-dom",
"redux",
"react-redux",
"async",
"requirejs",
"immutable"
],
"target": "es5",
"module": "amd",
"removeComments": true,
"allowUnreachableCode": true,
"moduleResolution": "node",
"lib": [
"es2015",
"dom"
]
},
"include": [
"./public/**/*.ts",
"./public/**/*.tsx"
]
}
let me know if this helped.
now i see what hot-reloader is. The compiler does not understand AMD module enclosures, so you will need to rewrite them in ES6 import syntax, e.g.:
import * as Application as from "js/application"
Application.start();
the compiler will generate a hot-reloader.js file that has the define for you.
The TS docs say that for AMD the module resolution should be 'classic'; but I guess since I am using ES6 import syntax (for the most part), I should use moduleResolution: 'node'?
The TS docs say that for AMD the module resolution should be 'classic'; but I guess since I am using ES6 import syntax (for the most part), I should use moduleResolution: 'node'?
I did not know where the @hot-reloader were coming from originally, and assumed they were private npm repos. i then looked at your snippets and figured it is your own files.
classic is correct. node follows nodeJs module resolution, that means import ... from "./foo" will resolve to either ./foo.js or ./foo/index.js, the second being wrong in AMD.
sorry for the confusion.
so is it working now?
my code runs fine; but it still compiles with unnecessary errors
my goal is to get 0 compile errors (obviously) but I still see a few related to RequireJS/TS integration:
10 const globalRequire = window.require;
~~~~~~~
public/js/hot-reloader.tsx(10,30): error TS2339: Property 'require' does not exist on type 'Window'.
20 requirejs.config({
72 });
public/js/main.tsx(20,18): error TS2345: Argument of type '{ enforceDefine: false; waitSeconds: number; baseUrl: string; bundles: { 'optimized/bundles/commo...' is not assignable to parameter of type 'RequireConfig'.
416 declare var require: Require;
~~~~~~~
node_modules/@types/requirejs/index.d.ts(416,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'require' must be of type 'NodeRequire', but here has type 'Require'.
import hotReloader = require('@hot-reload-handler');
~~~~~~~~~~~~~~~~~~~~~
public/js/application.tsx(4,30): error TS2307: Cannot find module '@hot-reload-handler'.
import config = require('@config');
~~~~~~~~~
public/js/application.tsx(5,25): error TS2307: Cannot find module '@config'.
TS doesn't recognize these modules even though they are OK. I am still looking for a mechanism to tell the tsc compiler about the modules that are loaded via the requirejs.config paths.
There must be a heavy-handed way to just tell tsc that these imports are loaded via RequireJS _network dependencies._
@hot-reload-handler and @config are defined by my requirejs.configpaths, but TS doesn't know about them. How can I tell TS about them?
Also I see this error unrelated to RequireJS:
93 function startProgressBar() {
~~~~~~~~~~~~~~~~
public/js/hot-reload-handler.tsx(93,18): error TS1252: Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'. Modules are automatically in strict mode.
I am trying to get rid of that error, how can I turn off strict mode with tsc?
All of the above errors should be avoidable. I would really love some help to fix these.. Can I share my project with you?
declare var require: Require;
you do not need this.
import hotReloader = require('@hot-reload-handler');
did you add a path mapping entry for it? e.g.
"paths": {
"@hot-reload-handler": [ "js/hot-reload-handler"]
},
or just
"paths": {
"@*": [ "js/*"]
},
function startProgressBar() {
I think the error there is self-explanatory, you either need to make this a const startProgressBar = function () or move it out of the if block. the behavior of functions in blocks have changed in ES6.
nice, thanks let me try it, your explanation is clearer now
but this line of code:
declare var require: Require;
is not in my project, I think it's a dependency...I think it's in here
node_modules/@types/requirejs/index.d.ts(416,13)
It's really close to working
is there a way to do something like this:
```js
"paths": {
"@config": [ false]
},
or
```js
"paths": {
"@config": [ "empty:"]
},
I just want to ignore module resolution for the @configpath
I tried explicitly declaring the paths in my tsconfig.json, same problem

is there a way to escalate this issue with a ticket? Would love to solve this, I will do anything! thanks for your help
I would really love it if TS had 1st class support for RequireJS / AMD :)
Just FYI some of the TS errors were resulting from:

e.g.
416 declare var require: Require;
~~~~~~~
node_modules/@types/requirejs/index.d.ts(416,13): error TS2403: Subsequent variable declarations must have the same type. Variable 'require' must be of type 'NodeRequire', but here has type 'Require'.
Why are you using the node.js types if you're using RequireJS? That's the source of the require conflict.
@blakeembrey you're probably right! for my front-end tsconfig I should probably get rid of
"types": [
"node", // get rid of this
I have two tsconfig.json files, one for backend one for frontend; the frontend config only includes the public directory, the backend config is everything but public directory.
I tried putting requirejs for the frontend config and node for the backend config and I get the same issues
I just want to ignore module resolution for the @configpath
in a .d.ts file add:
declare module "@config";
I tried explicitly declaring the paths in my tsconfig.json, same problem
what is your baseUrl? can you share your project?
yep, will share, thanks; note that I have tsconfig.json for the backend and tsconfig-fe.json for the frontend:
https://github.com/ORESoftware/hr4r2
to build the project you can use
./build.sh
and you should see the compile errors I mention above
since @hot-reload-handlerand @hot-reloader are both .tsx files, can't I just point "paths" to those files, instead of pointing "paths" to d.tsfiles? I am not sure I understand the reason why d.ts exists if there are all .ts/tsx files.
Also regarding:
import * as Application as from "js/application"
Application.start();
I am not sure if that will work for RequireJS since that will create a module, but what I need is an executable file/script. So I left that code alone without altering it to TS module syntax code.
So the main issues were in tsconfig. PR sent to address these: https://github.com/ORESoftware/hr4r2/pull/1
the error message you were getting about require with "subsequent declarations" is because @types\node\index.d.ts and@types\requirejs\index.d.ts both define a function called require and the compiler does not know which one to pick. you do not depend on @types/node, but @types/uuid does, and that what causes the issue. the fix for this issue is for https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/uuid/index.d.ts#L6 not to have this line.
the remaining issues seem self-explanatory to me.
@mhegazy I don't think it's possible to fix the uuid definition until TypeScript supports https://github.com/Microsoft/TypeScript/issues/7753 because removing Buffer from that definition is incorrect. It's a universal module that supports both node.js and browsers.
I think you can define a buffer in both, just make sure they are structurally compatable.
@mhegazy thanks so much for helping me out with this, the project compiles much better now
one thing I don't understand
you pared this (in tsconfig-fe.json):
"types": [
"lodash",
"react",
"react-dom",
"redux",
"react-redux",
"redux-thunk",
"async",
"requirejs",
"socket.io",
"socket.io-client",
"immutable",
"uuid",
"whatwg-fetch"
],
down to this:
"types": [
"react",
"react-dom",
"whatwg-fetch",
"requirejs"
],
but I am using socket.io-client, async, redux, etc on the front-end. So...why don't I need to reference those in my front-end tsconfig?
thanks!
It's not a buffer on the front-end though, it's an array. It's only a buffer in node and TypeScript doesn't support the ability to define universal module like that.
Then there should be uuid-node and uuid-browser?
@ORESoftware
redux and reduc-thunk packages already carry a .d.ts file with them, so no need to install @types\redux, as a matter of fact, that package is empty, it only has a readme file that tells you it is not needed.@mhegazy How would that work when TypeScript doesn't know which one to resolve when you install @types/uuid?
Edit: Sorry for the thread within the thread, I'm happy to move this to the other issue I have open. I just don't see how you intend to workaround this when people need to able to use TypeScript with universal modules.
it won't :), you will have to add a mapping from "uuid" : ["uuid-node"] or "uuid" : ["uuid-browser"] .
@mhegazy In the path mapping section? If that works, it sounds like a decent solution. I guess the same goes for a module author then, tell their TypeScript users to use path mapping if they're using a browser? E.g. "uuid": "uuid/browser" - would that work? What about recursive support for this, if someone publishes a module that uses x but that x has a browser or node.js version? What about people building modules on top of something like uuid and need to use the types? They can no longer do import x = require('uuid') since path mapping only works at the top level.
Edit: If it helps, I do have half a dozen examples of this that I'm stuck on supporting with TypeScript. For instance, I want to provide support for browsers using https://github.com/blakeembrey/node-servie as request/response interfaces but I can't today because TypeScript doesn't know how to require the browser version (doesn't expose the buffer method but might support blobs, for instance). Even if path mapping worked here, it'd just break when a different module is published using servie (e.g. popsicle uses it as the interface layer but now people using the browser version of popsicle end up with the server version of servie). Anyway, that's what the other issue is for, just trying to figure out if maybe it can be resolved today already if there's recursive path mapping.
@blakeembrey I'd like to subscribe to that other issue. Can I have a link 馃尮
@basarat It was https://github.com/Microsoft/TypeScript/issues/7753, issue for "node browser resolution" so it's possible to model "browser" resolution.
Most helpful comment
So the main issues were in tsconfig. PR sent to address these: https://github.com/ORESoftware/hr4r2/pull/1
the error message you were getting about require with "subsequent declarations" is because
@types\node\index.d.tsand@types\requirejs\index.d.tsboth define a function calledrequireand the compiler does not know which one to pick. you do not depend on@types/node, but@types/uuiddoes, and that what causes the issue. the fix for this issue is for https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/uuid/index.d.ts#L6 not to have this line.the remaining issues seem self-explanatory to me.