LoginSignup
0
0

CDNから読み込んだ(Moduleではない従来型の)JSライブラリに対して、後付けで型を適用する方法

Last updated at Posted at 2024-04-29

はじめに

CDNからJSライブラリを読み込むと常にany型となってしまい、VSCodeのサポート(IntelliSense)を利用することができません

image-4.png

ところが、VSCodeは(賢いので)ヒントを与えてあげると、型を認識できるようになります

  • CDNから読み込んだライブラリだけではなく、型定義のないJavaScriptの変数、関数に後付けで型を適用することができます
  • (VSCodeに組み込まれている)TypeScriptの機能を利用
    • 設定ファイル(tsconfig.json)やコンパイラ(tsc)は不要です(ファイルの拡張子は.jsのままで大丈夫です)

最初にまとめると

  • 想定する環境

    • VSCode+JavaScriptの(npmを利用しない従来型)プロジェクト
    • CDNから読み込んだライブラリと同じライブラリがnpmに存在する(無くても自分で型定義を書くことは可能)
    • npmのパッケージに型定義ファイルが含まれている(最近は大抵含まれている)
  • 型定義のやり方(下のどちらか、組み合わせて利用も可能)

    1. JSDoc@type { import("<ライブラリ名>") }で型定義を行う
    2. global.d.tsファイルを追加して、アンビエント宣言を行う

後付けで型定義を行うライブラリ(の紹介)

cowsay

cowsayとは、メッセージをつぶやくウシのアスキーアートを生成するプログラム(Unixのコマンドの1種)です

$ cowsay Hello!
  _______________________
 < Hello! >
  -----------------------
         \   ^__^
          \  (oo)\_______
             (__)\       )\/\
                 ||----w |
                 ||     ||
  • JavaScriptにも移植(npm package)されており、node環境であれば下記のように簡単に利用できます
const cowsay = require('cowsay');
console.log(cowsay.say({ text: 'Hello!' }));
  • CDN利用の場合は下記のように利用します
  <script src="//unpkg.com/cowsay@1.6.0/build/cowsay.umd.js"></script>
  <script type="text/javascript">
    const said = cowsay.say({ text: 'I am a cow!' });
    console.log(said);
  </script>

※cowsayにはnpmのパッケージもあり、module形式を利用すれば型定義も自動的に読み込まれます(ただし、バンドルが必要になるので、従来型アプリに組み込むのは手間がかかる)

手順

cowsayをCDNから読み込んで実行する

  • cowsayの最新版は1.6.0
  • umd版を読み込みます(グローバル変数cowsay経由で呼び出しできる)
index.html
<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title>cowsay</title>
</head>
<body>
  <script src="//unpkg.com/cowsay@1.6.0/build/cowsay.umd.js"></script>
  <script src="index.js"></script>
</body>
</html>

cowsayを利用するjs

index.js
const said = cowsay.say({ text: 'I am a cow!' });
console.log(said);

動作確認

npx http-server

Available on:
  http://192.168.3.7:8080
  http://127.0.0.1:8080
  http://172.28.112.1:8080
Hit CTRL-C to stop the server

ブラウザのコンソールで牛がしゃべりました

image-1.png

グローバル変数cowsayに型定義を行う

npmからcowsayパッケージをインストール

型定義が欲しいので、npmでcowsaiをインストールします

(ただし、この時点ではCDNから読み込んだグローバル変数には型定義が反映されません)

npm init -y
npm i npm i cowsay@1.6.0

型定義ファイルは node_modulesの中にあるindex.d.tsファイルです

image-5.png

次に、グローバル変数cowsayと、型定義の紐づけを行います(VSCodeがわかるように)

JSDocの方が簡単ですがグローバル変数へ直接型定義ができません(すこし工夫が必要)。アンビエント宣言の方が違和感なく使えます

グローバル変数への型定義その1:JSDoc

JavaScriptの変数と型を紐づけするためにJSDocの@typeとimportを利用します

残念ながらグローバル変数に型定義する構文がないため、グローバル変数から値を取り出した値に対して、型の定義を行います

index.js
/**
 * @type { import("cowsay") }
 */
const cowsay = window['cowsay'];  // グローバル変数をローカル変数にセットすると同時に型定義を行う

const said = cowsay.say({ text: 'I am a cow!' });
console.log(said);
  • VSCodeが型を認識するようになりました

image-3.png

閑話休題(JavaScriptファイルで型チェックを有効にする)

jsファイルの先頭に//@ts-checkを追加すると、TypeScriptコンパイラによる型チェックが有効になります(VSCodeの機能)

グローバル変数は未定義のためエラーになることがわかります

index.js
//@ts-check
const said = cowsay.say({ text: 'I am a cow!' });
console.log(said);

cowsayという変数を定義なしで使っているのでエラーになってしまいます

image-1.png

※jsファイルが多くて、コメントを挿入するのが面倒な場合、TypeScriptを導入し(VSCodeの)型チェック機能だけを利用する方法もあります

npm i -D typescript
  • tsconfig.jsonに最低限これだけ記載すれば、全.jsファイルの型チェックを行ってくれるようになります
tsconfig.json
{
  "compilerOptions": {
    "allowJs": true,  // trueにすることでcheckJsを有効化できる
    "checkJs": true, // JavaScriptファイルのエラーチェックを有効化する
  },
}

グローバル変数への型定義その2:アンビエント宣言

TypeScriptの型定義方法の1つにアンビエント宣言がという方法があります

アンビエント宣言は、変数、関数が「存在する」ことを(TypeScript)コンパイラに伝える機能です。ここではグローバル変数cowsayがどこかに存在する(ので未定義エラーにしないでねと伝える)ことと、その型定義がどこにあるか?を記述します

型定義ファイル (.d.ts)

アンビエント宣言(declare)について理解する

本来はTypeScriptの機能ですが、VSCodeは型定義ファイル~.d.tsがあると自動的に読み込んで型を認識してくれるのでそれを利用します

型定義ファイルを作成する

global.d.tsファイルを作成します(拡張子が「.d.ts」であれば、ファイル名は任意です)

global.d.ts
// グローバル変数'cowsay'に型(.\node_modules\cowsay\index.d.ts)を適用する
declare var cowsay: typeof import('cowsay');

node_modulesから型情報を読み込むことなく自分で定義することもできます(大変ですが)

動作確認

アンビエント宣言のおかげで、VSCodeが型を認識してくれるようになりました

index.js
//@ts-check
const said = cowsay.say({ text: 'I am a cow!' });
console.log(said);

image-2.png

おまけ:関数の引数に型の指定を行う(JSDoc)

型定義をimport('パッケージ名')で読み込むことができる

/**
 * @param {import('cowsay')} cowsay
 * @param {string} text
 * @returns {string}
 */
function random_think(cowsay, text) {
  return cowsay.think({ text });
}

console.log(random_think(cowsay, '呼んだ?'));
0
0
0

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
0
0