この記事では、わざわざTypeScriptでnpmライブラリ開発したいという読者を対象としています。
とはいえ今どきはVS Codeさんという素晴らしいエディターのおかげもあって、型が提供されていないnpmライブラリは使いづらい立場にあります。
では早速ですが、TypeScriptで"Hello だれだれ"とコンソールに表示されるnpmライブラリを開発してみましょう。
基本的なnpmライブラリ開発の知識
この記事では「TypeScriptで」npmライブラリ開発することに主眼を置きたいため、基本的なnpmライブラリ開発の知識は「本当にやさしいnpmライブラリ開発入門」くらいは知っている前提で進めます。
package.json
のあれこれ
私の趣味は人の書いたpackage.json
を見ることです。(趣味悪いでしょうw)
ではまずは今回お題にするpackage.json
を見ていただきましょう。
{
"name": "hello-world-typescript",
"version": "1.0.0",
"main": "dist/index.js",
"license": "MIT",
"files": [
"dist"
],
"scripts": {
"build": "tsc",
"prepublishOnly": "npm run build"
},
"devDependencies": {
"typescript": "^3.3.4000"
}
}
とても綺麗ですよね。
ひとつひとつ意味があるので解説していきます。
package.json#name
npmライブラリの名前です。require('xxx')
のxxx
にあたるアレです。
package.json#version
npmライブラリはこのバージョン情報を毎回インクリメントして公開する必要があります。
TypeScriptが一度3.3.3333
というアレなバージョンをつけてしまったために、3.3.4
にできずに3.3.4000
になってしまったのは、笑えない笑える話として有名かもしれませんね。
package.json#main
ここに相対パスで有効なJavaScriptファイルが指定されていないとrequire('xxx')
できません。
今回はTypeScriptのビルド結果を読み込ませたいので、dist/index.js
になっています。
package.json#files
package.json
のfiles
プロパティは、使う人と使わない人がいると思います。
Webpackのinclude
オプションとexclude
オプションに似ていて、前者はpackage.json
のfiles
プロパティ、後者は.npmignore
です。
要はnpmはライブラリをnpm publish
コマンドで公開する際に、files
プロパティが指定してあればそれらのみを公開対象とします。
TypeScriptはtsc
コマンドでビルドする前提なので、files
プロパティにビルド結果フォルダを指定してやると楽だよ、という話になるわけです。
package.json#scripts
npm run xxx
を作れるプロパティですね。
npm run build
は実際にはtsc
コマンドを実行するところはみなさんお分かりかと思います。
prepublishOnly
がニッチなやつで、npm publish
をする「前に」必ず実行されるという意味になります。
今回はnpm run build
を必ず走らせてからライブラリ公開したいので、これを指定しています。(開発したのにビルド忘れてバージョンしか上がらなかったという事故を防ぐやつです。)
ちなみに、scripts
プロパティにはいくつかのマジックがありまして、それが今回のpre
にあたります。
例えばnpm run xxx
を実行する場合、prexxx
とpostxxx
を作成しておくと、それぞれ実行前と後に指定されたコマンドが叩かれたりします。
(なかなか便利なのですが駆使しすぎるとpackage.json
の管理が大変になるので注意。)
tsconfig.json
お待たせしました。
みなさんこれが早く見たかったですよね。
ご査収ください。
{
"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"moduleResolution": "node",
"strict": true,
"skipLibCheck": true,
"declaration": true,
"pretty": true,
"newLine": "lf",
"outDir": "dist"
}
}
ニッチなところだけ説明していきますね。
target
とmodule
はどのようなライブラリの種類にするのか(Node.jsで利用されるのか、ブラウザで利用されるのか等)によって変わってきます。今回は最新のNode.jsで叩くだけのライブラリですのでtarget: "esnext"
のmodule: "commonjs"
になります。Node.jsで利用される場合は常にmodule: "commonjs"
と覚えておいても構いません。
せっかくなのでTypeScriptにきちんと仕事をさせたい。なのでstrict: true
にします。
でもライブラリのエラーが無限に出てくることがあるので、それは無視するためにskipLibCheck: true
にします。
型定義をきちんと出力したいので、declaration: true
にします。
あとWindowsで開発したい方は、クロスプラットフォームでの利用を念頭に改行コードをLFに寄せます。そのためにnewLine: "lf"
します。
(例えばコマンドラインツール系のnpmライブラリをWindowsで開発した際に、Linux等で実行するとエラーになります。それを防ぐために改行コードをLFに寄せます。)
最後に今回はdist
フォルダにコンパイル結果を出力したいので、outDir: "dist"
とします。
TypeScriptでnpmライブラリ開発
やっと開発に入りますが、もう終わったようなものです。
function hi(name: string) {
console.log(`Hello ${name}`);
}
export default hi;
ビルドしてみます。
$ npm run build
dist
にビルド結果が出ました。
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
function hi(name) {
console.log(`Hello ${name}`);
}
exports.default = hi;
型定義も出力されています。
declare function hi(name: string): void;
export default hi;
最後にnpmライブラリとして公開してみます。
$ npm publish
ちゃんとnpm run build
(tsc
)されてから公開されましたね。
まとめ
- TypeScriptはコンパイル作業が必要なので、事前準備がひと手間かかる
- それをクリアすればTypeScriptでもサクサクnpmライブラリ開発ができる!
いかがでしたでしょうか。
私は.NETやらTypeScriptやらでMicrosoftさんにはお世話になっていますが、型安全なのはとても気持ちいいです。
少しでも皆さまのお役に立てたらと思います。
では良いTypeScriptライフを!!