Edited at

TypeScriptでnpmライブラリ開発ことはじめ

この記事では、わざわざTypeScriptでnpmライブラリ開発したいという読者を対象としています。

とはいえ今どきはVS Codeさんという素晴らしいエディターのおかげもあって、型が提供されていないnpmライブラリは使いづらい立場にあります。

では早速ですが、TypeScriptで"Hello だれだれ"とコンソールに表示されるnpmライブラリを開発してみましょう。


基本的なnpmライブラリ開発の知識

この記事では「TypeScriptで」npmライブラリ開発することに主眼を置きたいため、基本的なnpmライブラリ開発の知識は「本当にやさしいnpmライブラリ開発入門」くらいは知っている前提で進めます。


package.jsonのあれこれ

私の趣味は人の書いたpackage.jsonを見ることです。(趣味悪いでしょうw)

ではまずは今回お題にするpackage.jsonを見ていただきましょう。


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.jsonfilesプロパティは、使う人と使わない人がいると思います。

Webpackのincludeオプションとexcludeオプションに似ていて、前者はpackage.jsonfilesプロパティ、後者は.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を実行する場合、prexxxpostxxxを作成しておくと、それぞれ実行前と後に指定されたコマンドが叩かれたりします。

(なかなか便利なのですが駆使しすぎるとpackage.jsonの管理が大変になるので注意。)


tsconfig.json

お待たせしました。

みなさんこれが早く見たかったですよね。

ご査収ください。


tsconfig.json

{

"compilerOptions": {
"target": "esnext",
"module": "commonjs",
"moduleResolution": "node",
"strict": true,
"skipLibCheck": true,
"declaration": true,
"pretty": true,
"newLine": "lf",
"outDir": "dist"
}
}

ニッチなところだけ説明していきますね。

targetmoduleはどのようなライブラリの種類にするのか(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ライブラリ開発

やっと開発に入りますが、もう終わったようなものです。


src/index.ts

function hi(name: string) {

console.log(`Hello ${name}`);
}

export default hi;


ビルドしてみます。

$ npm run build

distにビルド結果が出ました。


dist/index.js

"use strict";

Object.defineProperty(exports, "__esModule", { value: true });
function hi(name) {
console.log(`Hello ${name}`);
}
exports.default = hi;

型定義も出力されています。


dist/index.d.ts

declare function hi(name: string): void;

export default hi;

最後にnpmライブラリとして公開してみます。

$ npm publish

ちゃんとnpm run build(tsc)されてから公開されましたね。


まとめ


  • TypeScriptはコンパイル作業が必要なので、事前準備がひと手間かかる

  • それをクリアすればTypeScriptでもサクサクnpmライブラリ開発ができる!

いかがでしたでしょうか。

私は.NETやらTypeScriptやらでMicrosoftさんにはお世話になっていますが、型安全なのはとても気持ちいいです。

少しでも皆さまのお役に立てたらと思います。

では良いTypeScriptライフを!!