What is the importance of including "declare var angular" while working with Typescript and AngularJS?

I've been working on an AngularJS 1.7 application that's coded entirely in TypeScript, and there's always been one thing bothering me.

Within my app.module.ts file, I have this piece of code that doesn't sit right with me:
declare var angular;
This is necessary for the

this.app = angular.module('app'...

to transpile and function correctly.

I've experimented with a few solutions:

1) Switching out declare var angular; with
import angular from "angular";
transpiles without issues, but then the browser throws an error:

Uncaught (in promise) TypeError: angular_1.default.module is not a function

2) Substituting declare var angular; with

import * as angular from "angular";

also transpiles smoothly, but again, leads to a similar browser error:
Uncaught (in promise) TypeError: angular.module is not a function

3) Swapping declare var angular; with
import ng from "angular";
and using ng.angular.module or ng.module fails to transpile altogether.

In the end, the only method that has worked for me is sticking with declare var angular;

While everything functions properly, it just doesn't feel quite right. Why is this step necessary? Am I missing something? Is there a cleaner approach?


Details:

  • Utilizing Visual Studio 2017/2019
  • TypeScript version 3.3
  • SystemJS (not RequireJS)
  • AngularJS version 1.7.8
  • @types/angular version 1.6.54

package.json

"devDependencies": {
    "@types/angular": "^1.6.54",
    ...
},
"dependencies": {
    "angular": "~1.7.8",
    ...
}

tsconfig.json

{
    "compileOnSave": true,
    "compilerOptions": {
        "baseUrl": ".",
        "paths": {
            "*": [ "node_modules/types/*", "node_modules/*" ],
        },
        "module": "system",
        "target": "es6",
        "sourceMap": true,
        "lib": [ "es6", "dom" ],
        "allowSyntheticDefaultImports": true,
        "outFile": "./app/everything.js",
        "moduleResolution": "node",
        "types": [
            "angular",
            "jquery"
        ]
    },
    "include": ["app/**/*"],
    "exclude": ["node_modules", "lib"],
    "strict": true
}

app.module.ts

declare var angular;
...
export class App {
    app: ng.IModule;

    constructor() {
        this.app = angular.module('app', [
        ...
        ]);
    }

    public run() {
        this.app.run([
        ...
        ]);
        ...
    }

index.html

...
<script src="lib/systemjs/system.js"></script>
<script src="lib/angular/angular.min.js" type="text/javascript"></script>
...
<script src="app/everything.js" type="text/javascript"></script>

<script>
    System.config({
        map: {
            "angular": "lib/angular",
            ...
        },
        packages: {
            "angular": { main: "angular.min.js", defaultExtension: "js" },
            ...
        }
    });
    System.import("app.module")
        .then(function (app) {
            let a = new app.App();
            a.run();

            angular.element(function () {
                angular.bootstrap(document, ['app']);
            });
        });
</script>

Answer №1

Your Typescript types, specifically the @types/angular package, rely on the presence of the angular variable to assign their types.

In a typical scenario, you would import Angular like this: import angular from "angular", allowing the types to be applied to the newly created angular variable smoothly.

However, if you are already loading Angular globally in your HTML using a <script> tag, importing it again via import angular from "angular" might cause conflicts and lead to potential issues.

By using declare var angular, you are indicating to Typescript that the angular variable exists somewhere in the global scope, even though it hasn't been explicitly imported into the current file.

This approach ensures that:

  • Typescript won't throw errors about an undefined Angular.
  • The types from @types/angular will still be associated with your angular variable.

At runtime, as long as the angular object is indeed present on the window object, everything should function correctly.

This workaround becomes necessary when transitioning to bundlers like Webpack or SystemJS. Once you eliminate the global Angular script from your index.html, you can proceed to import Angular into your TypeScript files and remove the declare var statement.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Understanding the appropriate roles and attributes in HTML for a modal backdrop element in a TypeScript React project

Trying to create a Modal component using React and TypeScript with a feature that allows closing by clicking outside. This is being achieved by adding a backdrop element, a greyed out HTML div with an onClick event calling the onClose method. Encountering ...

Having trouble getting anime.js to function properly in an Ionic 3 project?

I have been attempting to incorporate anime.js into my Ionic 3 project, but I keep encountering an error when using the function anime({}) in the .ts file. Error: Uncaught (in promise): TypeError: __webpack_require__.i(...) is not a function TypeError: _ ...

Angular allows for the creation of dynamic content, much like the append function in jQuery

I am currently working with Angular to create a dynamic star rating system. I have implemented a function to generate the code for the stars dynamically, but unfortunately, they are not showing up on the page. Can anyone help me troubleshoot this issue? B ...

`the issue of $scope object not being passed correctly to ng-if and ng-class ternary conditions

**app.js:** $scope.servers = [ {name:'SQL Server', status:"up"}, {name:'Web Server', status:"down"}, {name:'Index Server', status:"down"} ]; **index.html:** <table> ...

Using AngularJS client and Flask server for a RESTful call, one can include the

I am currently facing an issue where I need to send a REST request from my AngularJs client to a Flask server. The problem arises when one of the ids (key) in the request contains a forward slash. Interestingly, if the key does not contain a slash, the re ...

Angular is having trouble with binding

What seems to be the issue in this code snippet? JSFiddle. function SecondCtrl($scope, Data) { $scope.data = Data; $scope.reversedMessage = function(message) { return message.split("").reverse().join(""); }; } ...

Issue: Attempting to send a POST request to the specified API endpoint for creating a product category resulted in a 500 Internal Server Error

My current task involves inserting data into a table using the POST method with an Angular service function. angular.module("productCategoryModule") .factory("productCategoryService",productCategoryService); productCategoryService.$inject = ['$http& ...

Angular JS: How to dynamically add and remove checkboxes in ng-repeat?

Currently, I have successfully implemented a Miller column using Angular and Bootstrap. To view the functionality in action, you can check out the code snippet at this link. In the second column of my setup, clicking on a word opens up the third column. ...

In the process of developing a custom Vue component library with the help of Rollup and VueJS 3

My goal is to develop a custom Vue component library using rollup and Vue.js. The process went smoothly with Vue2, but I encountered issues parsing CSS files with Vue3. To address this, I updated the dependencies in the package.json file. package.json { ...

Seeking guidance on transforming a thunk-based create store into a promise-based one. Any suggestions?

I am currently transitioning my app from loading data from local storage to using Firebase. Firebase always returns a promise, so I need to adapt my existing store to work with the new Firebase data. Here is the original code snippet: export const loadSta ...

Saving any type of file in SQL Server with a field type of varbinary(max) can be achieved by utilizing Angular with ASP.NET Core to create a REST API

I am currently facing an issue while attempting to save a file, such as an image, in the Microsoft SQL Server Management Studio through asp .NET core for the Rest API. I have managed to create a base64 representation of the file, but I am unsure about the ...

Having trouble executing partial views with node.js and AngularJS?

I have been working on my AngularJS application and everything functions correctly when I browse it. However, I've encountered an issue while trying to configure Express. The main page displays fine, but when I click on the hyperlinks to load partial ...

perform the directive function following the ng-cloak execution

I am having an issue with my content using the ng-cloak directive, as I would like to retrieve the height of an element using innerHeight() within a directive. However, when I use innerHeight(), the element is hidden by ng-cloak so the result is always 0. ...

Utilize AngularJS to securely retrieve a zip file through a Spring-powered RESTful web service

AngularJs is still unfamiliar territory for me, and I'm looking to develop code that can download a zip file through a Spring-based RESTful web service upon clicking a 'download' button. The web service functionality is all set up, but I nee ...

How can you incorporate a module for typings without including it in the final webpack bundle?

As I venture into the realm of Webpack, I am faced with the challenge of transitioning from TypeScript 1.x to TypeScript 2. In my previous projects, I typically worked with TypeScript in one module using separate files, TSD for typings, and compiling throu ...

Using Angular.js, apply the "visible" class conditionally based on a variable

My Cordova application is built with angular.js and consists of the following 2 files: app.html <div ng-controller="MyAppCtrl as myApp" ng-class="myApp.isWindows() ? 'windows' : ''"> and app.controller MyAppCtrl.$inject = [&ap ...

Automatically pass on parameters from a universal function

If I have an object with functions that return numbers: const obj = { foo() { return 1; } bar() { return 2; } baz(num: number) { return num; } } The expected output of typeof obj would be: { foo: () => number; bar: () => number; baz ...

Error Encountered When Using SQLite Ionic Plugin

For my Ionic application, I am in the process of creating a database test using information from the original documentation found here. However, upon creating and running the app, I encountered the following error on the terminal: **Uncaught TypeError: Ca ...

Issues with Angular authentication: HTTP POST request not being sent

UPDATE: I had a small oversight with my submit button placement, but it's all sorted out now (turns out the request wasn't sent because my function wasn't called, a classic mistake). Furthermore, the reason why authentication always succ ...

Ways to conceal a component based on a specific condition?

In my Angular 8 application, I need to dynamically hide a component based on a specific condition. The condition I want to check is: "status === EcheqSubmissionStatus.EXPIRED" Initially, I attempted the following approach: EcheqProcessComponent templat ...