使用带有自定义界面的 Google Adsense 的 TypeScript

TypeScript using Google Adsense with custom Interface

我按照教程在我的 Angular 应用程序中使用 Google Adsense。 这是结果:

在index.html中:

<!-- Global site tag (gtag.js) - Google Analytics -->
<script>
  (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
  })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

  ga('create', 'UA-1223823-NOT-MY-ACTUALLY-ID', 'auto');  // Change the UA-ID to the one you got from Google Analytics

</script>

这是我的 app.component.ts:

import {Component} from '@angular/core';
import {NavigationEnd, Router} from '@angular/router';

// declare ga as a function to set and sent the events
declare let ga: Function;  // <-- Here is the "Error"

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'news-bootstrap';
  constructor(public router: Router) {
    // subscribe to router events and send page views to Google Analytics
    this.router.events.subscribe(event => {

      if (event instanceof NavigationEnd) {
        ga('set', 'page', event.urlAfterRedirects);
        ga('send', 'pageview');
      }
    });
  }
}

TsLint 不喜欢 'declare let ga: Function' 行:TSLint: Don't use 'Function' as a type. Avoid using the `Function` type. Prefer a specific function type, like `() => void`.(ban-types)

这如何与接口一起工作?

我需要一个带有方法 setPage(urlAfterRedirects: string) 和 sendPageView() 的接口,其属性 ga 通过 index.html js 脚本链接。这还要'the right way'来做吗?在这种情况下 'Avoid using the Function type' 的最佳方法是什么?

EDIT1:我可以移动 ga('create', 'UA-1223823-NOT-MY-ACTUALLY-ID', 'auto');界面也有功能?

问题

当您声明一个变量的类型为 Function 时,您是在告诉打字稿“这是一个函数,其中包含任意数量的任意类型的参数和 returns 任何类型的参数。”那里有很多未知数。

当您尝试调用该函数时,typescript 无法检查您是否使用正确的参数调用它,因为它不知道参数应该是什么。它要求您提供的是定义函数特定签名的类型。

简单的解决方案

对于 ga 函数,我们可以更具体一点或更具体一些。这是涵盖您正在进行的两个调用的“更具体一点”:

type GA = (action: string, field: string, value?: string) => void;

这表示我们的 type GA 是一个函数,它接受两个或三个参数,这些参数都是字符串并且 returns 什么都没有。

复杂性

实际上有 an alternative syntax 用于调用 'set' 这也是有效的,但上面的 type GA.

定义不支持

您可以通过将字段和值作为单独的参数传递给函数来设置一个字段和一个值,这就是您正在做的事情。

ga('set', 'page', '/about');

但您也可以传递字段和值的对象:

ga('set', {
  page: '/about',
  title: 'About Us'
});

lots and lots of fields 但并非所有都是 string,因此“更具体”将是一个类型定义,可确保您的所有字段名称都有效并且所有的值与特定字段匹配。

幸运的是 there's an existing types package 已经完成了这项工作。看起来他们正在声明一个全局变量 ga(以及其他一些变量),因此您根本不需要 declare let ga。 (但我无法在 TS Playground 中使用它。)

抽象

您还询问了关于创建一个界面,作为您和底层 ga 对象之间的外观,使其使用起来更直观。这不是必需的,但可能很有用。 Here's an article 我发现这样做是为了事件跟踪,他们使用打字稿来描述他们想要跟踪的特定事件,因为 ga 几乎允许任何事情。

您的界面将是这样的:

interface MyGaTracker {
    setPage(urlAfterRedirects: string): void;
    sendPageView(): void;
}

您可以使用 class 或普通对象来实现它:

export const Tracker: MyGaTracker = {
    setPage: (urlAfterRedirects: string): void => {
        ga('set', 'page', urlAfterRedirects);
    },
    sendPageView: (): void => {
        ga('send', 'pageview');
    }
}

Typescript Playground Link