docs/project/module-resolution.md
TypeScript's module resolution tries to model and support the real world modules systems / loaders there (commonjs/nodejs, amd/requirejs, ES6/systemjs etc.). The most simplest lookup is relative file path lookup. After that things become a bit complex because of the nature of magical module loading done by various module loaders.
You import modules like foo or ./foo. For any file path lookup TypeScript automatically checks for a .ts or .d.ts or .tsx or .js (optionally) or .jsx (optionally) file in the right order depending upon context. You should not provide a file extension with the module name (no foo.ts, just foo).
An import with a relative path e.g.:
import foo = require('./foo');
Tells the TypeScript compiler to look for a TypeScript file at the relative location e.g. ./foo.ts with respect to the current file. There is no further magic to this kind of import. Of course it can be a longer path e.g. ./foo/bar/bas or ../../../foo/bar/bas just like any other relative paths you are used to on disk.
The following statement:
import foo = require('foo');
Tells the TypeScript compiler to look for an external module in the following order:
--module commonjs or have set --moduleResolution node then its looked up using the node modules resolution algorithm.baseUrl (and optionally paths) then the path substitutions resolution algorithm kicks in.Note that "foo" can be a longer path string e.g. "foo/bar/bas". The key here is that it does not start with ./ or ../.
A module declaration looks like:
declare module "foo" {
/// Some variable declarations
export var bar:number; /*sample*/
}
This makes the module "foo", importable.
The node module resolution is actually pretty much the same one used by Node.js / NPM (official nodejs docs). Here is a simple mental model I have:
foo/bar will resolve to some file : node_modules/foo (the module) + foo/barTODO.