124
94

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 5 years have passed since last update.

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

Last updated at Posted at 2019-03-23

この記事では、わざわざ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ライフを!!

124
94
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
124
94

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?