Search code examples
angularjstypescripttypescript1.8definitelytyped

DefinitelyTyped: What does 'export = _;' means


I'm trying to use angular-material with a ng-metadata project and I run into some issues.

I use DefinitelyTyped for angular material and the first lines are:

declare module 'angular-material' {
  var _: string;
  export = _;
}

In my main.ts I try to import { ngMaterial } from 'angular-material';

then bootstrap( AppComponent, [ 'ngMaterial' ] ); but all I got is:

Error:(3, 10) TS2305: Module ''angular-material'' has no exported member 'ngMaterial'.

I don't know what I am doing wrong


Solution

  • When being used through ES6 or TypeScript, a common pattern that Angular modules follow is that they'll use their name as the default export. For example, one of the modules in my application looks like this:

    const session = angular.module("smSession", [])
        .service("session", SessionService)
        .component("smLogin", Login)
        .config(routes)
        .run(loginRedirect);
    
    export default session.name;
    

    The reasoning behind this is that it makes the syntax for declaring an Angular module's dependencies cleaner; for example:

    import angular from "angular";
    import ngAnimate from "angular-animate";
    import ngMaterial from "angular-material";
    import uiRouter from "angular-ui-router";
    
    let module = angular.module("myApp", [ ngAnimate, ngMaterial, uiRouter ]);
    

    If they instead exported the entire module, you'd have to do this:

    let module = angular.module("myApp", [ ngAnimate.name, ngMaterial.name, uiRouter.name ]);
    

    So this is why the main module declaration for angular-material looks like it does - they're simply representing the fact that all you can import from the package is that one string representing the module's name. The rest of the type definitions are ambient - you can just use the angular.material namespace anywhere in your application without having to do an import.

    EDIT: To clarify, here's the actual source of the file that gets imported when you import ngMaterial:

    // Should already be required, here for clarity
    require('angular');
    
    // Load Angular and dependent libs
    require('angular-animate');
    require('angular-aria');
    
    // Now load Angular Material
    require('./angular-material');
    
    // Export namespace
    module.exports = 'ngMaterial';
    

    Notice that require('./angular-material') doesn't return anything - that import effectively just runs the file that sets up the Angular module behind the scenes (effectively the same sort of code as in my examples). The only thing being exported from the module is the name.