Typescript: Global variables from @types/angular not available when other imports/exports are present

Created on 23 Sep 2016  路  9Comments  路  Source: microsoft/TypeScript

TypeScript Version: 2.0.3
Visual Studio Code Version: 1.5.3
Compilation method: tsc -p .

Code:
https://github.com/joselee/ts-2.0-types-issue

Description:
When I install declaration files using npm install --save @types/angular, VS Code (and tsc) complains about the global variable angular, if there are other import/export statements in the same file. The error given is: TS2686: Identifier 'angular' must be imported from a module.
foo_error_2686

If there are no imports or exports in the same file where I try to use angular, no complaints:
foo_noerror_2686

I tried to work around this issue with import * as angular from 'angular', but this gives the error: TS2307: Cannot find module 'angular'. Without this import, auto-completions work fine in VS code (even though it complains - _first image_). But once I put this import in, auto-completions stop.
foo_failed_import

Expected behavior:
Global variables from libraries should be available in all .ts files, even if there are other imports/exports.

Actual behavior:
Global variables are only available when no imports or exports are present. Otherwise, compilation errors occur. Also, adding "types": ["angular"] to tsconfig.json does not help.

Note:
@types/lodash does not seem to be affected the same way. _ can be used and has auto-completions without complaint, even with other imports/exports.

Duplicate

Most helpful comment

@joselee If you specify "moduleResolution": "node", in your tsconfig.json you can write

import * as angular from 'angular';

That said, there are some aspects of how angular.d.ts is written that I find confusing. It begins with
/// <reference types="jquery" /> and contains multiple export as namespace ns clauses. Later on it augments the global jQuery declaration. However the shape of jquery.d.ts is completely different, following the classic, pre-umd TypeScript pattern of declaring a global and an ambient external module. I don't know how these kinds of declarations interoperate.

All 9 comments

I am also experiencing something very similar. I have some globals that I am importing using the new @types folder. Underscore specifically is giving me grief. Everything compiles fine until I add an import to the file with the global dep.

tsconfig.json

tsconfig

Import that causes things to go off the rails

import

Error Message

post addition

8255 is the reason for this.

I think it is actually good behavior because you will indeed not have the module available unless you load its source as a global as well. If you are using modules, you need to commit to them.

@aluanhaddad, I don't believe this is the intended behavior. Reasoning is that other libraries, which also expose global variables (such as lodash and jQuery), don't require you to import anything in order to use them. Angular should behave the same way, because _globals should be global_.

Here you can see that it is only Angular that shows an error about requiring the import:
angular_jquery_lodash

Further, I am unable to import the 'angular' module, even if I wanted to commit to using modules:
import_modules_error

I've updated the project to include jquery, @types/jquery, lodash, and @types/lodash

@joselee If you specify "moduleResolution": "node", in your tsconfig.json you can write

import * as angular from 'angular';

That said, there are some aspects of how angular.d.ts is written that I find confusing. It begins with
/// <reference types="jquery" /> and contains multiple export as namespace ns clauses. Later on it augments the global jQuery declaration. However the shape of jquery.d.ts is completely different, following the classic, pre-umd TypeScript pattern of declaring a global and an ambient external module. I don't know how these kinds of declarations interoperate.

@aluanhaddad "moduleResolution: "node" allows me to import the 'angular' module. Thanks!

So then, is this an issue with angular.d.ts not exposing globals correctly? Or are we now supposed to explicitly import variables, meaning jQuery and lodash (for example) need to be updated to behave similarly? Either way, they should be made to behave consistently.

@joselee I believe the jQuery definitions need to be updated with

export as namespace jQuery;
export as namespace $;

but I'm not 100% sure. There's a lot of churn in this area. I agree we need a consistent way of doing this, it's causing a lot of headaches.

+1 on this, I'd like to update to TS 2.x but running into this error when doing so

To get this working until further and better solutions are available, I'm using Webpack with this added to webpack.config.js

    externals: {
        'angular': 'angular',
        'jquery': 'jquery'
    }

I found about it on React & Webpack guide. Even though the guide author said in https://github.com/Microsoft/TypeScript/issues/10178#issuecomment-263638106

The only reason I wrote that in the tutorial is because using externals cuts down on bundle-time. If you use the global React variable without importing, you can't easily switch to modules later on, whereas imports give you the flexibility of using either given your loader.

It still works for now and allows Webpack to bundle TS files without issues when using angular or other globally exposed variables.

My full webpack.config.js

module.exports = {
    entry: './app.ts',
    output: {
        filename: 'app.js',
        path: path.resolve(__dirname, 'build')
    },
    module: {
        rules: [
            {
                test: /\.tsx?$/,
                loader: 'awesome-typescript-loader',
                exclude: /node_modules/,
            }
        ]
    },
    resolve: {
        extensions: ['.tsx', '.ts', '.js']
    },
    devtool: 'inline-source-map',

    externals: {
        'angular': 'angular',
        'jquery': 'jquery'
    }
}
Was this page helpful?
0 / 5 - 0 ratings