typescript - 在angular 2 typescript 中导入gapi.auth2

标签 typescript angular google-api-js-client

我试图在 typescript 中从 Google gapi.auth2 导入一些类或函数。但是即使我在打字目录中正确添加了 gapi.auth2 类型,下面的代码也永远无法工作。
import { GoogleAuth } from 'gapi.auth2';
我总是有错误:
Error TS2307: Cannot find module 'gapi.auth2'
我应该使用一些相对目录搜索,例如'../../typings/gapi.auth2'吗?

或者我使用gapi的方式是完全错误的?

谢谢!

最佳答案

使用 gapigapi.auth对于 Angular2,使用 NPM 安装类型脚本定义。

npm install --save @types/gapi
npm install --save @types/gapi.auth2
这将安装两个包,@types/gapi@types/gapi.auth2node_modules文件夹并将配置保存在 package.json .
检查您的 node_modules文件夹以检查它们是否正确安装。如果您的 Angular 应用程序被称为“主应用程序”,您应该看到:
main-app/
  node_modules/
    @types/
      gapi/
      gapi.auth2/
red pill and blue pill设想:
  • 如果没有提供任何 types compiler options应该不需要明确添加 gapigapi.auth2"types": [] tsconfig.json 中的编译器选项|因为
  • 默认所有可见 @types编译过程中包含包。
  • 包裹在 node_modules/@types (任何封闭文件夹的)被认为是可见的。
  • 但是 .如 types已经指定,TSConfig Reference说明您必须添加 gapigapi.auth2否则默认情况下不会包含它们。在这一节中,编辑 tsconfig.json包括新的 gapigapi.auth2类型:

  • {
       "compilerOptions": {
         "types": ["jest", "lodash", "gapi", "gapi.auth2"]
        }
    }
    
    此时,如果你有足够的动力,可以阅读Typescript Module Resolution ,可以直接跳到 Node.js 如何解析模块 :

    Node will look for your modules in special folders named node_modules. A node_modules folder can be on the same level as the current file, or higher up in the directory chain. Node will walk up the directory chain, looking through each node_modules until it finds the module you tried to load.


    出于这个原因,您不需要在 Angular2 服务或组件中添加对类型定义的引用(或在您使用 gapigapi.auth2 的任何地方)。
    但是,如果您确实添加了对 gapi 的引用或 gapi.auth2 TypeScript 定义,它必须引用 .ts使用 npm install 安装的文件(注意,你必须保留 /// 否则你会得到一个错误):
    /// <reference path="../../node_modules/@types/gapi/index.d.ts" />
    
    路径是相对的,因此您的路径可能会因.ts 的位置而异。文件与您安装 TypeScript 定义的位置有关。
    无论您是添加了显式引用还是使用了 TypeScript 的 Node 模块解析机制,您仍然需要在 .ts 中声明您的变量。文件,以便 Angular 知道窗口 gapi编译时变量。添加 declare var gapi: any;给您的 .ts文件,但不要将其放在类定义中。我把我的放在任何进口的下面:
    // You may not have this explicit reference.
    /// <reference path="../../node_modules/@types/gapi/index.d.ts" />
    import { NgZone, Injectable, Optional } from '@angular/core';
    declare var gapi: any;
    
    使用其他 JavaScript 库 TypeScript documentation值得一读以了解我们从所有这些工作中得到了什么。
    接下来,加载 gapi来自您自己的函数的客户端(可能在 Angular 服务中):
     loadClient(): Promise<any> {
         return new Promise((resolve, reject) => {
             this.zone.run(() => {
                    gapi.load('client', {
                        callback: resolve,
                        onerror: reject,
                        timeout: 1000, // 5 seconds.
                        ontimeout: reject
                    });
             });
        });
    }
    
    这个功能很重要,这就是为什么......
    首先,请注意我们正在拨打 gapi.load配置对象而不是 回调 . GAPI reference可以使用状态:
  • 库完成时调用的回调函数
    加载。
  • 一个封装了各种配置参数的对象
    对于这种方法。只需要回调。

  • 使用配置选项允许我们拒绝 加载库超时或只是错误时的 Promise。根据我的经验,加载库比初始化它失败的频率更高——这就是为什么配置对象比回调更好的原因。
    其次,我们正在包装 gapi.load
    this.zone.run(() => {
      // gapi.load
    });
    
    NgZone.run is documented和状态

    Running functions via zone.run allows you to reenter Angular zone from a task that was executed outside of the Angular zone [...]


    这正是我们在调用 gapi.load 后想要的。离开 Angular 区域。忽略这一点可能会导致很难调试的非常时髦的结果。
    三、loadClient()返回一个已解决的 promise - 允许调用者选择他们如何处理 gapi.load .例如,如果我们的 loadClient方法属于 Angular 服务,apiLoaderServce ,组件可以使用 ngOnInit加载 gapi :
    ngOnInit(): void {
        this.apiLoaderService.loadClient().then(
            result => this.apiLoaded = true,
            err => this.apiLoaded = false
        );
    }
      
    
    曾经gapi.load已被调用,gapi.client将准备就绪,您应该使用它来使用您的 API key 、OAuth 客户端 ID、范围和 API 发现文档来初始化 JavaScript 客户端:
    initClient(): Promise<any> {
        var API_KEY = // Your API key.
        var DISCOVERY_DOC = // Your discovery doc URL.
        var initObj = {
            'apiKey': API_KEY,
            'discoveryDocs': [DISCOVERY_DOC],
        };
    
        return new Promise((resolve, reject) => {
            this.zone.run(() => {
                gapi.client.init(initObj).then(resolve, reject);
            });
        });
    }
    
    通知我们的 friend NgZone.run再次使用以确保重新输入 Angular 区域。
    在实践中,我添加 loadClient()initClient()到 Angular 服务。在高级 Angular 组件(通常就在 app 组件下方)中,我在 ngOnInit 中加载和初始化:
    ngOnInit(): void {
        this.apiLoaderService.loadClient().then(
            result => {
                this.apiLoaded = true;
                return this.apiLoaderService.initClient()
            },
            err => {
                this.apiFailed = true;
            }
        ).then(result => {
            this.apiReady = true;
        }, err => {
            this.apiFailed = true;
        });
    }
    
    最后,您需要将gapi 脚本文件添加到您的文件中。
    <html>
      <head>
        <script src="https://apis.google.com/js/api.js"></script>
    
    您不得使用 async defer属性,因为它们会导致 Angular 世界在 gapi 库加载之前进入。
    <!-- This will not work. -->
    <html>
      <head>
        <script async defer src="https://apis.google.com/js/api.js"></script>
    
    我之前建议通过加载 gapi library 的本地缩小副本来保持快速页面加载速度。在 /main-app/src/assests文件夹和导入:
        <html>
          <head>
            <script src="assets/api.js"></script>
    
    然而,我强烈推荐 不做这个。谷歌可能会更新 https://apis.google.com/js/api.js你的客户会崩溃。我已经被这两次捕获了。最后最好从 //apis.google.com/js/ 导入并将其保留为阻塞调用。

    关于typescript - 在angular 2 typescript 中导入gapi.auth2,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38091215/

    相关文章:

    angular - Angular|Ionic 中“未找到 [自定义组件] 的组件工厂”

    javascript - Search Console API 的发现文档 URL?

    javascript - Uncaught ReferenceError : gapi is not defined at makeApiCall?

    selenium - 很抱歉,在使用 Selenium 的自动化测试环境中加载 Google API 时,您的计算机或网络可能会发送自动查询错误

    javascript - 在 keydown 上,为什么值的 console.log 与将值分配给对象不同?

    javascript - NestJs 如何在特定时间每天运行 3 次 cron 作业

    angular - 错误 TS1086 无法在环境上下文中声明访问器。获取 firebaseUiConfig() : NativeFirebaseUIAuthConfig

    Angular - 在 Http.post 中接收并返回 Observable<T> 响应

    typescript - “void”返回类型未在 TypeScript 中检查——防止 float promise ?

    angular - 在清理组件期间使用取消订阅错误测试 Angular 组件