How to install Typescript typings for google maps
Asked Answered
Y

15

77

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'.

Yogi answered 17/3, 2016 at 15:16 Comment(3)
It doesn't look like Google has anything in the Typings registry. You'll need to download the type definitions directly.Haeckel
Thanks I tried that and have updated my questionYogi
The official typings are @types/google.maps. developers.google.com/maps/documentation/javascript/… npm i -D @types/google.mapsAckerley
S
134

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.

Seeker answered 11/3, 2017 at 8:59 Comment(26)
If I use this src: "maps.googleapis.com/maps/api/js" I'm getting Runtime Error doMapInitLogic is not defined. If I use this src: "maps.googleapis.com/maps/api/…" and remove the onload I'm getting message: "initMap is not a function", name: "InvalidValueError", stack: "Error↵ Please assist with a complete example or tutorialAnhydride
doMapInitLogic() is a function which you can create (you can rename it whatever you like). Did you come right?Seeker
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...Anhydride
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...Anhydride
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 developers.google.com/maps/documentation/javascript/tutorialSeeker
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 documentationAnhydride
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'.Seeker
I've been following 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?Anhydride
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)Seeker
This is by far the best solution aroundMitch
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.Tachymetry
@BarryMcNamara public mapRef: google.maps.Map; seems to work for me. I've updated my answer with some type definitions I use.Seeker
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.Tachymetry
@BarryMcNamara, not entirely sure what you mean :) but wouldn't you use google.maps, instead of window.google.maps?Seeker
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.Tachymetry
Can somebody explain the meaning of import {} from '@types/googlemaps'? seems like empty importUfa
@Ufa 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.Seeker
After some struggling with webpack it became clear that this line is not needed really. Namespace definition could be imported by triple-slash directive /// <reference path="..." />. 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.Ufa
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.Seeker
@StephenPaul I've found that I've enough reps :-) But you should agree to publish itUfa
Beautiful explanation. I've accepted your edits. I learned something new :)Seeker
Hey, I think I found an even cleaner version: /// <reference types="googlemaps" />: 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. typescriptlang.org/docs/handbook/triple-slash-directives.html This removes the need for ugly relative paths!Managing
I've successfully followed this approach, mixing it with dynamic component loading: blog.angularindepth.com/…Burdensome
You should youse --save-dev and not --save for @types installsAnagram
removing only "types": [] in tsconfig.app.json, it resolved! NiceNewark
2021: i had to add "google.maps" to types, not "googlemaps"Proto
Y
18

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

npm install --save @types/google-maps
Yogi answered 14/11, 2016 at 8:22 Comment(2)
Tested in Ionic2 RC3: you need "@types/google-maps" plus "typings install dt~google.maps --global" and also "/// <reference path="./../../../typings/globals/google.maps/index.d.ts" />"Borkowski
Yes! Searched for this for like 5 hours.. I had to install @types as mentioned above but still have to add the line /// <reference path="./../../../typings/globals/google.maps/index.d.ts" /> above my imports in the component that I wanted to use this in.Kathikathiawar
B
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
  }
}
Benedikt answered 28/11, 2016 at 22:7 Comment(2)
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'.Surfactant
@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.Bowser
K
13

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" />
Kriemhild answered 7/2, 2019 at 19:44 Comment(3)
This is the only solution that worked for me on VS Code. For me, I did not change the tsconfig and did not added any d.ts files.Futhark
After much pain, this solution worked for me in getting build to work on Vercel + next.js. Thank you!Amory
As of now it seems the correct reference type is /// <reference types="google.maps" />Millian
S
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"
   ],
   ...
}
Selfdelusion answered 1/4, 2019 at 9:14 Comment(1)
Thanks. I didn't get any errors in browser but got in IDE for google namespace. import '@types/googlemaps'; is important.Malvinamalvino
T
10

typings install google.maps --global

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

Tnt answered 17/3, 2016 at 16:12 Comment(2)
looks like i had the commands in the wrong order then as I had tried thisYogi
Typings has changed the term 'ambient' to 'global' starting from [v1.0.0] (github.com/typings/core/releases/tag/v1.0.0) typings install google.maps --global or typings install dt~google.maps --globalDecarbonize
A
10

As of now the correct way to install is:

typings install dt~google.maps --global [--save]
Artemas answered 5/8, 2016 at 10:19 Comment(0)
D
10

As of typescript 2

npm install --save @types/googlemaps

Add typeroots to your tsconfig

{
  "compilerOptions": {
    "typeRoots": ["./node_modules/@types/"]
  }
}
Dodder answered 17/4, 2017 at 21:46 Comment(2)
Why is this typeRoots necessary? That should be the default.Pharos
@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.Managing
B
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"
  ],
Botsford answered 8/9, 2018 at 11:59 Comment(0)
B
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

Brainwash answered 19/6, 2018 at 18:48 Comment(0)
S
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

Seeker answered 8/2, 2020 at 11:1 Comment(1)
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://mcmap.net/q/264451/-how-to-install-typescript-typings-for-google-maps. Other than that import they are just adding a bunch of controls which may or may not be needed.Ottinger
C
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
Cognizance answered 21/5, 2021 at 10:11 Comment(0)
S
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

Strobile answered 4/12, 2020 at 7:37 Comment(0)
N
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

Nabokov answered 27/9, 2019 at 22:31 Comment(3)
@types/google__maps and @types/googlemaps are for entirely different libraries with the former being for node and the latter for the browser.Ackerley
Y, that's why i mentioned specifically in a nodejs environment. :)Nabokov
Theres also @types/google.mapsScoff
C
0

I tried everything from above and finally I got it working.

If you use "@angular/google-maps" (in my case "^17.2.1"), then add it to the imports in your app.module.ts

import { GoogleMap } from '@angular/google-maps';

@NgModule({
  imports: [
    GoogleMap,
  ],
}
Carriecarrier answered 2/3 at 18:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.