简体   繁体   English

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

[英]TypeScript using Google Adsense with custom Interface

I followed a Tutorial to use Google Adsense in my Angular App.我按照教程在我的 Angular 应用程序中使用 Google Adsense。 This is the out come:这是结果:

in the index.html:在 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>

And this is my app.component.ts:这是我的 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 doesn't like the line '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) 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) TSLint: Don't use 'Function' as a type. Avoid using the `Function` type. Prefer a specific function type, like `() => void`.(ban-types)

How does this work with interfaces?这如何与接口一起工作?

I need a interface with the methods setPage(urlAfterRedirects: string) and sendPageView() with the attributes ga that is linked via the index.html js script.我需要一个带有 setPage(urlAfterRedirects: string) 和 sendPageView() 方法的接口,其属性 ga 通过 index.html js 脚本链接。 Is this even 'the right way' to do it?这甚至是“正确的方法”吗? What is the best way to 'Avoid using the Function type' in this case?在这种情况下,“避免使用Function类型”的最佳方法是什么?

EDIT1: And can I shift the ga('create', 'UA-1223823-NOT-MY-ACTUALLY-ID', 'auto'); EDIT1:我可以改变 ga('create', 'UA-1223823-NOT-MY-ACTUALLY-ID', 'auto'); function to the interface, too?接口也有函数?

Problem问题

When you declare that a variable has the type Function you are telling typescript "this is a function that any some amount of arguments which are any type and returns anything."当您声明一个变量的类型为Function您是在告诉打字稿“这是一个函数,任何数量的参数都是任何类型并返回任何内容。” There's quite a lot of unknowns there.那里有很多未知数。

When you try to call that function, typescript can't check if you are calling it with the right arguments because it doesn't know what the arguments are supposed to be.当您尝试调用该函数时,typescript 无法检查您是否使用正确的参数调用它,因为它不知道参数应该是什么。 What it's asking you for is a type that defines the specific signature of the function.它要求您提供一种定义函数特定签名的类型。

Simple Solution简单的解决方案

For the ga function we can get a little bit more specific or a lot more specific.对于ga函数,我们可以得到更具体或更具体的信息。 Here's an "a little bit more specific" that covers the two calls that you are making:这是一个“更具体的”,涵盖了您正在拨打的两个电话:

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

This says that our type GA is a function which takes two or three arguments which are all strings and returns nothing.这表示我们的type GA是一个函数,它接受两个或三个参数,这些参数都是字符串并且不返回任何内容。

Complexities复杂性

In reality there's an alternative syntax for calling 'set' which is also valid but would not be supported by the above definition for type GA .实际上,有一种用于调用 'set' 的替代语法,它也是有效的,但上述type GA定义不支持。

You can set one field and one value by passing the field and value as separate arguments to the function, which is what you're doing.您可以通过将字段和值作为单独的参数传递给函数来设置一个字段和一个值,这就是您正在执行的操作。

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

But you can also pass an object of fields and values:但您也可以传递字段和值的对象:

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

There are lots and lots of fields and not all of them are string , so the "a lot more specific" would be a type definition that makes sure that all your field names are valid and that all of the values match the specific field.很多字段,并不是所有字段都是string ,因此“更具体”将是一个类型定义,可确保所有字段名称都有效并且所有值都与特定字段匹配。

Fortunately there's an existing types package which has done that work already.幸运的是,有一个现有的类型包已经完成了这项工作。 It looks like they are declaring a global var ga (along with a few others), so you wouldn't need your declare let ga at all.看起来他们正在声明一个全局 var ga (以及其他一些),所以你根本不需要你的declare let ga (But I can't get this working in the TS Playground.) (但我无法在 TS Playground 中使用它。)

Abstraction抽象

You're also asking about creating an interface which acts as a façade between you and the underlying ga object, making it more intuitive to use.您还要求创建一个界面,作为您和底层ga对象之间的外观,使其使用起来更加直观。 This is not a necessity but it can be useful.这不是必需品,但它可能很有用。 Here's an article I found about doing this for event tracking, where they use typescript to describe the specific events they want to track since ga allows pretty much anything. 这是我发现的一篇关于为事件跟踪执行此操作的文章,他们使用打字稿来描述他们想要跟踪的特定事件,因为 ga 几乎允许任何事情。

Your interface would be this:你的界面是这样的:

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

You could implement it using a class or a plain object:您可以使用类或普通对象来实现它:

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

Typescript Playground Link 打字稿游乐场链接

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM