75

How can it be done - I've tried combinations of

typings install [googlemaps | google.maps] [--ambient] --save

and end up with variations on this error

typings ERR! message Unable to find "googlemaps" for "npm" in the registry.

Per Amy's suggestion, I've also download to the relevant directory and added

/// <reference path="main/ambient/google.maps/google.maps.d.ts" />

to my main.d.ts (a file which is clearly being read as I don't get other errors).

And I can't find anything on the web to answer the question

My end goal is to get rid of this sort of error

error TS2503: Cannot find namespace 'google'.

Simon H
  • 20,332
  • 14
  • 71
  • 128
  • 1
    It doesn't look like Google has anything in the [Typings registry](https://github.com/typings/registry). You'll need to [download the type definitions directly](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/googlemaps). –  Mar 17 '16 at 15:47
  • Thanks I tried that and have updated my question – Simon H Mar 17 '16 at 16:10
  • 1
    The official typings are @types/google.maps. https://developers.google.com/maps/documentation/javascript/using-typescript `npm i -D @types/google.maps` – Justin Poehnelt Jan 25 '22 at 21:54

14 Answers14

131

So what makes this exceptional is that the maps script needs to be downloaded separately from your app bundle. It's not your typical npm install where you get your .js and .ts nicely packaged for consumption.

TLDR: the typings can be installed via npm but the .js script must be downloaded via a <script> tag (for SPAs this tag can be appended to your web page on-the-fly to improve initial load time of your app, which is what I do).

My recommended path is as follows:

Install

npm install --save-dev @types/googlemaps

Import

import {} from 'googlemaps';

Load & Use (this function makes sure the maps script is only appended to the page once, so that it can be called over and over)

addMapsScript() {
  if (!document.querySelectorAll(`[src="${googleMapsUrl}"]`).length) { 
    document.body.appendChild(Object.assign(
      document.createElement('script'), {
        type: 'text/javascript',
        src: googleMapsUrl,
        onload: () => doMapInitLogic()
      }));
  } else {
    this.doMapInitLogic();
  }
}

Remember, the maps script must be appended to the page and the script must be downloaded before anything else happens. If you're using Angular, for example, I wrap the addMapsScript() logic in an observable and put in my map components route resolver.

Use the types (Type definitions include, but are not limited to):

const mapRef: google.maps.Map;
const bounds: google.maps.LatLngBounds;
const latLng: google.maps.LatLng;

Get Rid of the warning:@types/googlemaps/index.d.ts' is not a module.

Add a file at your projects root directory called index.d.ts and insert the following:

declare module 'googlemaps';


Update 01.06.2018 (findings of @DicBrus):

In order to import google namespaces and get rid of annoying error "Cannot find namespace 'google'" you should ensure that you've imported namespace definitions in @types/googlemaps

There are two ways to do it:

  1. triple-slash directive

    /// /node_modules/@types/googlemaps/index.d.ts" /> Worked fine, but not so elegant.

Documentation could be found here: https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html

  1. Ensure that it is imported in tsconfig.json and since it is imported you do not need to import something additionally

Detailed manual is here: https://www.typescriptlang.org/docs/handbook/tsconfig-json.html

you should check two subsections under compilerOptions: typeRoots and types

By default all type definitions under node_modules/@types are imported unless you specified exactly what you need.

In my particular case I had following section:

"types": []

It disables automatic inclusion of @types packages.

Removing this line re-solved issue for me, as well also adding triple-slash directive helped. But I chose the second solution.

As for the "empty" import, I didn't found any explanation how and why it works. I suppose that it does NOT import any module or class, but it does import namespaces. This solution is not suitable for me, since IDE marks this import as "not used" and it can be easily removed. E.g, webstorm's command Ctrl+Alt+O - prettifies code and removes all unnecessary imports.

Stephen Paul
  • 37,253
  • 15
  • 92
  • 74
  • If I use this src: "https://maps.googleapis.com/maps/api/js" I'm getting Runtime Error doMapInitLogic is not defined. If I use this src: "https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&callback=initMap" and remove the onload I'm getting message: "initMap is not a function", name: "InvalidValueError", stack: "Error↵ Please assist with a complete example or tutorial – iOSAndroidWindowsMobileAppsDev May 10 '17 at 14:16
  • 2
    doMapInitLogic() is a function which you can create (you can rename it whatever you like). Did you come right? – Stephen Paul May 10 '17 at 14:49
  • could I please ask. Can the language of choice in doMapInitLogic() be javascript? I am trying to avoid typescript. Where do I put this function, if I may ask. Is there a tutorial I can follow cause I am clueless... – iOSAndroidWindowsMobileAppsDev May 12 '17 at 06:48
  • the reason is that for the javascript api the power thereof is unlimited whereas with typescript there is no official library hence I am limited with what I can do... – iOSAndroidWindowsMobileAppsDev May 12 '17 at 06:54
  • 2
    Yes, it can be Javascript, but then I'm wondering why you're looking at this question about Typescript? ;) If you are using Javascript only, I'd suggest you start by checking out Googles official docs https://developers.google.com/maps/documentation/javascript/tutorial – Stephen Paul May 12 '17 at 06:55
  • I am exploring ionic 2 which uses angular 2 and typescript. Now the problem is that all the fancy maps an tuts are in javascript, as your link suggests. In looking up your answer I was trying to still use javascript in ionic 2. Pretty please assist with an example that still uses javascript in ionic 2 which requires usage of typescript for which there is no documentation – iOSAndroidWindowsMobileAppsDev May 12 '17 at 07:00
  • 3
    So, you actually do not need Typescript to use google maps, it's just nice to have type definitions while using the maps API. Now, you will still get a typescript error if you try to declare a new google.maps.Map - something like 'google is not defined'. What you can do to fix that is, at the top of your source file (outside your class) write 'declare const google'. – Stephen Paul May 12 '17 at 07:07
  • I've been following https://www.youtube.com/channel/UCo1uXpOZneIU6kkzzPvj5oQ and this guy does just as you say I should. However, the small changes like declare var google, declaring map:any, using this.map or even assigning that =this, then using that.map, or introducing additional variables, e.g. map to function definitions get more and more complicated as you demand more from the functionality. How can I use typings definitions to do the map logic in javascript directly? Isn't there a tut I can follow? – iOSAndroidWindowsMobileAppsDev May 12 '17 at 07:14
  • 1
    At one point I actually used raw Javascript for the maps in my typescript. Didn't seem too bad. Which specific video show that? Because some of these problems like 'assigning that=this' can be solved with es6 lambdas (no typescript) – Stephen Paul May 12 '17 at 07:39
  • This is by far the best solution around – Daniel Cardenas Aug 10 '17 at 15:28
  • So If I load the API like you do and then do `const gmaps = window["google"]["maps"]` is there a way I can give the API a type? Like `google.maps` except that doesn't work. – Barry McNamara Aug 16 '17 at 18:55
  • @BarryMcNamara `public mapRef: google.maps.Map;` seems to work for me. I've updated my answer with some type definitions I use. – Stephen Paul Aug 17 '17 at 05:10
  • That works for me as well. What I am asking about is the API itself which is loaded into `window.google.maps`. Currently I have to treat it as type `any` which is a bit unnerving when calling the constructors. – Barry McNamara Aug 17 '17 at 14:48
  • @BarryMcNamara, not entirely sure what you mean :) but wouldn't you use `google.maps`, instead of `window.google.maps`? – Stephen Paul Aug 17 '17 at 15:24
  • I'm doing stuff with Angular in which I am trying to make a custom GoogleMap class. I load the API by inserting a script tag like you do, but then in order to access `google.maps` I need to get it from the global `window` variable. I then store it in `this.api` for convenience. This is what I'm trying to give a type to. – Barry McNamara Aug 17 '17 at 19:58
  • 1
    Can somebody explain the meaning of `import {} from '@types/googlemaps'`? seems like empty import – DicBrus May 31 '18 at 11:54
  • @DicBrus good question! To this day, I haven't worked that one out and have yet to see that syntax elsewhere. All I know is that it seems to work with Webpack. If you have discovered any more info in this regard, I'd love to hear it. – Stephen Paul May 31 '18 at 12:27
  • 1
    After some struggling with webpack it became clear that this line is not needed really. Namespace definition could be imported by triple-slash directive /// . Another way to import it is to play with tsconfig.json file, in my case I edited "typeRoots" section. After adjusting it, I removed "empty" import and it works fine. Seems to me, that this empty import do not import any classes, modules and so on, but only namespaces. – DicBrus Jun 01 '18 at 15:04
  • 1
    Wow I'm so pleased that you figured that out. Well done :) I'm not sure if you have enough rep to edit my answer? Otherwise please let me know exactly what you changed in the ts-config. – Stephen Paul Jun 01 '18 at 15:10
  • 1
    @StephenPaul I've found that I've enough reps :-) But you should agree to publish it – DicBrus Jun 01 '18 at 16:52
  • Beautiful explanation. I've accepted your edits. I learned something new :) – Stephen Paul Jun 01 '18 at 17:14
  • 3
    Hey, I think I found an even cleaner version: `/// `: The process of resolving these package names is similar to the process of resolving module names in an import statement. An easy way to think of triple-slash-reference-types directives are as an import for declaration packages. https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html This removes the need for ugly relative paths! – seri Jun 26 '18 at 10:43
  • I've successfully followed this approach, mixing it with dynamic component loading: https://blog.angularindepth.com/dynamically-loading-components-with-angular-cli-92a3c69bcd28 – sucotronic Sep 06 '18 at 11:16
  • 1
    You should youse --save-dev and not --save for @types installs – EuberDeveloper Sep 27 '20 at 20:51
  • removing only `"types": []` in tsconfig.app.json, it resolved! Nice – darkziul Mar 02 '21 at 12:47
  • 5
    2021: i had to add "google.maps" to `types`, not "googlemaps" – xaphod Oct 19 '21 at 21:45
18

In practise, my use case is the Angular CLI, and there all I need is

npm install --save @types/google-maps
Simon H
  • 20,332
  • 14
  • 71
  • 128
  • Tested in Ionic2 RC3: you need "@types/google-maps" plus "typings install dt~google.maps --global" and also "/// " – Andrei Drynov Nov 25 '16 at 17:19
  • Yes! Searched for this for like 5 hours.. I had to install @types as mentioned above but still have to add the line /// above my imports in the component that I wanted to use this in. – slipperypete Apr 29 '17 at 10:38
15

I tested these steps on my ionic 2 project and it is works perfectly:

  1. install typings globally :

npm install typings --global
  1. install google.maps via typings

typings install dt~google.maps --global --save
  1. open tsconfig.json and add "typings/*.d.ts" to your "include" array as shown below (tsconfig.json).

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    "declaration": false,
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "lib": [
      "dom",
      "es2015"
    ],
    "module": "es2015",
    "moduleResolution": "node",
    "sourceMap": true,
    "target": "es5"
  },
  "include": [
    "src/**/*.ts",
    "typings/*.d.ts"
  ],
  "exclude": [
    "node_modules"
  ],
  "compileOnSave": false,
  "atom": {
    "rewriteTsconfig": false
  }
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
user2662006
  • 2,246
  • 22
  • 16
  • 1
    In my case i was missing the tsconfig.json part where "typings/*.d.ts". But now i'm facing a new problem. Huge amount of compiling errors all related to 'Duplicated Identifier'. – Becario Senior Feb 24 '17 at 13:14
  • @BecarioSenior you must have fixed it. Just for future reference. If you are adding your files in tsconfig.json(as step 3), remove typings/index.d.ts file contents because both are doing basically same thing and thus its loading google maps contents twice and hence duplicate error occurs. – Luckyy Apr 28 '17 at 09:45
12

I struggled to define the google object on the window, finally found a good way, by extending Window interface.

Just create a google-maps.d.ts file with this:

import '@types/googlemaps';

declare global {
  interface Window {
    google: typeof google;
  }
}

And add it to a directory called types at your root folder. Then point to this folder in your tsconfig.json file.

// tsconfig.json
compilerOptions: {
   ...
   "typeRoots": [
     "node_modules/@types",
     "types"
   ],
   ...
}
felixmosh
  • 32,615
  • 9
  • 69
  • 88
  • Thanks. I didn't get any errors in browser but got in IDE for google namespace. `import '@types/googlemaps';` is important. – Ankit.Z Sep 30 '22 at 11:22
10

typings install google.maps --global

You need the --global (used to be --ambient) flag to search DefinitlyTyped

Krzysztof Kowalczyk
  • 3,513
  • 28
  • 28
Mike Jerred
  • 9,551
  • 5
  • 22
  • 42
  • looks like i had the commands in the wrong order then as I had tried this – Simon H Mar 17 '16 at 16:14
  • 7
    Typings has changed the term 'ambient' to 'global' starting from [v1.0.0] (https://github.com/typings/core/releases/tag/v1.0.0) `typings install google.maps --global` or `typings install dt~google.maps --global` – HaRoLD May 22 '16 at 09:36
10

As of now the correct way to install is:

typings install dt~google.maps --global [--save]
Matyas
  • 13,473
  • 3
  • 60
  • 73
10

As of typescript 2

npm install --save @types/googlemaps

Add typeroots to your tsconfig

{
  "compilerOptions": {
    "typeRoots": ["./node_modules/@types/"]
  }
}
Johansrk
  • 5,160
  • 3
  • 38
  • 37
  • 2
    Why is this `typeRoots` necessary? That should be the default. –  Jun 02 '18 at 13:41
  • @torazaburo It's close, but not quite the same. Leaving `typeRoots` off means every `node_modules/@types` in every enclosing folder will be checked (potentially from unwanted parent folders). Restricting it to `./node_modules/@types/` makes it a little bit more predictable I guess. – seri Jun 26 '18 at 10:50
9

The easyest way is use a triple-slash directive. Fortunately, there's an alternative syntax available which takes advantage of the standard package resolution:

 /// <reference types="googlemaps" />
8

My solution (works for Vue2.x):

Install

npm install --save @types/googlemaps

Add script to index.html

<script src="https://maps.googleapis.com/maps/api/js?key=XXX&libraries=YYYY"></script>

Create in root folder types/index.d.ts

Put here the next lines:

/// <reference path="../node_modules/@types/googlemaps/index.d.ts" />
declare module 'googlemaps';

Open tsconfig.json and add "types/*.d.ts" to your "include" array.

  "include": [
    "src/**/*.ts",
    "src/**/*.tsx",
    "src/**/*.vue",
    "tests/**/*.ts",
    "tests/**/*.tsx",
    "types/**/*.d.ts"
  ],
Andrey Bulgakov
  • 423
  • 7
  • 10
5

Stephen Paul clearly explains everything, but there is something important to mention. tsconfigs can extend each other. And extended one can overwrite the parent one. In my case I had another tsconfig.app.json under app directory which has

types: []

arrays. As Stephen already explained this empty array overrides typeRoots. So just remove all types arrays in ALL related tsconfig files and ensure that

"typeRoots": ["node_modules/@types"]

is present. Needless to say that @types@googlemaps must be installed

Timothy
  • 3,213
  • 2
  • 21
  • 34
4

For users of Angular9+ I would STRONGLY recommend using their official component

Step 1: Installation:

npm install --save-dev @angular/google-maps

Step 2: Registration

@NgModule({
  imports: [
    GoogleMapsModule
  ]
})
export class AppModule { }

Step 3: Implementation

<google-map [center]="center" [options]="options"></google-map>
center = new google.maps.LatLng(-30.5595, 22.9375);
options: google.maps.MapOptions = {
  mapTypeId: 'hybrid',
};

See https://medium.com/angular-in-depth/google-maps-is-now-an-angular-component-821ec61d2a0 for a more detailed guide

Stephen Paul
  • 37,253
  • 15
  • 92
  • 74
  • If you look at the source code for @angular/google-maps you will see they are just using the triple-slash directive solution provided here: https://stackoverflow.com/a/54581130/10893. Other than that import they are just adding a bunch of controls which may or may not be needed. – Bryant Jul 28 '20 at 15:08
3

Well I have tried all the above without success in my angular 11 project, finally the official typing from google solved my issue :

npm install --save @types/google.maps
Moussa
  • 4,066
  • 7
  • 32
  • 49
1

If you face the error message Cannot find namespace ‘google’ while previewing, then you need to do two things.

  1. Install Google Map plugin

    npm install @google/maps

  2. Just import the google maps to app.component.ts file

    import { google } from '@google/maps';

Source: https://medium.com/javascript-in-plain-english/integrate-google-maps-to-your-angular-application-step-by-step-guide-3604aadb76d1

SwissCodeMen
  • 4,222
  • 8
  • 24
  • 34
Rutendo
  • 39
  • 2
0

The new @types/google__maps works perfectly for us. The original one(@types/googlemaps) was tricky and has many browser dependencies(like HTMLElement) which would fail the TS compiling if you use it in a nodejs environment.

npm install @types/google__maps -D

So we have googlemaps, google-maps, and google__maps in DefinitelyTyped. The difference are explained below: https://github.com/DefinitelyTyped/DefinitelyTyped/pull/29625#issuecomment-429207839

LeOn - Han Li
  • 9,388
  • 1
  • 65
  • 59