14
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Qiita Advent Calendar 2021
タイムリープTypeScript 〜TypeScript始めたてのあの頃に知っておきたかったこと〜
4日目の記事として
あの頃に知っていれば、こんなに遠回りしなかったgtag設定のエピソードをご紹介します。

  1. さいしょに
  2. 解決方法
  3. 初心者のあゆみ
  4. さいごに

さいしょに

window.gtag('config', 測定ID);

TypeScriptのプロジェクトで、このようにGoogle Analyticsの測定のみ記述すると
window.gtagの型が定義されていないことを指摘するエラーになります。

このエラーから正解にたどり着くまでを、当時をふりかえってまとめてみました。

解決方法

gtagの型定義が公開されているので、インストールすればよい。

@types/gtag.jsをインストールすると、window.gtagが型定義済みの状態になります。

# npmのプロジェクトへインストールする場合
npm install @types/gtag.js

# yarnのプロジェクトへインストールする場合
yarn add -D @types/gtag.js

初心者のあゆみ

こじらせポイントと、全体のながれをふりかえり
初心者がさまよった様子をみていきます。

こじらせポイント

2つの要素がこじらせて、解決まで時間がかかりました。

:innocent:
Type Searchの存在に気づいていなくて、型定義ファイルを見つけるコツがわかっていなかった

:innocent:
tsconfig.jsonの理解が浅いままtypesを設定していたため
@types/gtag.jsをインストールしただけでグローバルに使用できなかった。

tsconfig.jsonには、gtag.jsとは別のパッケージを導入するタイミングで設定したtypesがありました。

tsconfig.jsonのtypes
{
  "compilerOptions": {
    "types": ["hoge"]
  },
}

当時をふりかえる

おこった出来事、やったことを、順番にふりかえります。

  1. 型定義がないのでエラー
  2. windowの子要素へ型を追加できる?
  3. 苦肉のany回避
  4. 型定義をインストールしたけど反応がない…

型定義がないのでエラー

型定義のエラーを予感しつつ、とりあえずgtagを使うと
やっぱりエラーでした。

Property 'gtag' does not exist on type 'Window & typeof globalThis'.  TS2339

gtagはWindowの型にもTypeScriptのglobalThisの型にも存在しません

そうですよね。

:innocent: この時点でType Searchへアクセスし型定義を検索したら、もっと解決が早かった。

windowの子要素へ型を追加できる?

とはいえ、自分がつくった変数に型を設定できるのは知っているけれど
windowにぶら下がっていても型って設定できるもの?

エラーの文言でそのまま検索すると、windowの子要素にも型を設定できることがわかりました。

なるほど、declare globalというのを設定すると、windowの子供でも型がつけられた!

declare global {
  interface Window {
    gtag: any;
  }
}

anyがESLintにたしなめられていて気持ち悪いけど、エラーが解けて動くようになりました。

苦肉のany回避

anyのままは気持ち悪いけど、gtag.jsの型定義を手作りする根性もなかったので
もう少し検索してみました。

すると、gtagのイベンを発火させる関数をクッションにするやり方を知りました。

htmlへgtagを設定するついでに、発火させる自作の関数pageViewEventも設定し
declareではpageViewEventの型を設定してany回避しました。

htmlファイルのheaderに発火用のpegeViewEvent設置
<script async src="https://www.googletagmanager.com/gtag/js?id=測定ID"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag() {
    dataLayer.push(arguments);
  }
  gtag('js', new Date());
  // gtagページビュー送信イベントを実行
  function pageViewEvent(){
    window.gtag('config', 測定ID);
  }
</script>
発火イベントpageViewEventの型
declare global {
  interface Window {
    pageViewEvent: () => void;
  }
}
declareしているのでセーフ
window.pageViewEvent();

しかし、エラーもないしanyも使わない形にできたけど
ほんとうの意味で型を定義したわけではないのでは?

型定義をインストールしたけど反応がない…

実はこの時点で、
公開されているgtagの型定義があり、それ導入している解説記事を見つけていました。

しかし、手順にしたがってnpm installしても
window.gtagが型定義されている状態とならず、行き詰まっていました。

(ここで、しばらく諦めの期間に突入…)

pegeViewEventで騙し騙し動かしつつ、手がかりを検索していると
@types/gtag.jsが効いていなかった原因がみつかりました!

ただし、tsconfig.jsontypesが既に設定されている場合はグローバルに検出されません。
typesを取り除くか、gtag.jstypesに追加しましょう。
(Will Squireさんのアドバイス意訳)

tsconfig.jsonが影響してたんか…
こじらせポイントにあったよう、gtagを設定しようとしていたプロジェクトでは
typesにhogeが設定されている状態でした。

:innocent: typesを設定したとき、意味や影響を深堀りせずお手本どおりにしていた。

tsconfig.json
{
  "compilerOptions": {
    "types": ["hoge", "gtag.js"]
  },
}

こうして、導入の解説記事ではインストールするだけで型定義できていたのに
自分のプロジェクトでは型定義できなかった原因がわかり、全てが解決しました。

さいごに

この記事を書くために、当時あがいたキーワードで思い出し検索したのですが
あのときよりも多くの記事がみつかり
TypeScriptの盛り上がり、というか、もう定着してきている情勢を感じました。

まだまだ習熟度が浅いので、今後ともがんばって勉強します。

14
5
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
14
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?