[[TypeScript]]の[[npmパッケージ]]を作成するメモ。以下の記事を参考に。
<div class="link-card-v2">
<div class="link-card-v2-site">
<img class="link-card-v2-site-icon" src="https://spin.atomicobject.com/wp-content/uploads/cropped-AO-Favicon-512-32x32.png" />
<span class="link-card-v2-site-name">Atomic Spin</span>
</div>
<div class="link-card-v2-title">
How to Create an NPM Package in TypeScript from the Ground Up
</div>
<div class="link-card-v2-content">
Demystify the creation of a TypeScript NPM package by starting from the absolute minimum amount of code and buil ...
</div>
<img class="link-card-v2-image" src="https://spin.atomicobject.com/wp-content/uploads/Screenshot-2024-11-25-at-1.45.24-PM.png" />
<a href="https://spin.atomicobject.com/npm-package-typescript/"></a>
</div>
## まずは[[JavaScript]]で書かれた最小限のモノを
初めはシンプルに本質を理解すべしということだろう。やってみる。
### ライブラリプロジェクトの作成
```console
mkdir mimizou-libtest
cd mimizou-libtest
```
`name`のみを指定した[[package.json]]を作る。publishしなければ`version`は必ずしも必須ではないらしい。[[スコープ (npm)|スコープ]]を指定する。
`mimizou-libtest/package.json`
```json
{
"name": "@tadashi-aikawa/mimizou-libtest"
}
```
そして、`{hello: (name: string): string}`な[[プロパティ (TypeScript)|プロパティ]]をもつ。
`mimizou-libtest/index.js`
```js
module.exports = {
hello: (name) => "Hello, " + name + "!"
};
```
### ライブラリ利用プロジェクトの作成
別のディレクトリで`@tadashi-aikawa/mimizou-libtest`を呼び出す[[CLI]]のコードを作成。
```console
cd ../
mkdir mimizou-cli
cd mimizou-cli
```
`mimizou-cli/index.js`
```js
const { hello } = require('@tadashi-aikawa/mimizou-libtest');
console.log(hello('world'));
```
これだけだと、`@tadashi-aikawa/mimizou-libtest`は[[モジュール (TypeScript)|モジュール]]として認識されない。そこでいつものように[[npm install]]する。違いはパッケージ名ではなくパスを指定するということだ。
```console
npm install ../mimizou-libtest
```
[[package.json]]は未作成だったが、勝手に作成された。
`mimizou-cli/package.json`
```json
{
"dependencies": {
"@tadashi-aikawa/mimizou-lib-test": "file:../mimizou-libtest"
}
}
```
これで[[IDE]]でも補完が効く。実行すれば期待通り動く。
```console
$ node index.js
Hello, world!
```
## ライブラリ利用プロジェクトの[[TypeScript]]化
### [[TypeScript]]のインストール
`mimizou-cli`のプロジェクトを[[TypeScript]]対応する。
```console
npm i -D typescript
```
### [[tsconfig.json]]ベースのインストール
[[tsconfig.json]]には[[TSConfig bases]]を使う。
```console
npm install -D @tsconfig/node18
```
`mimizou-cli/tsconfig.json`
```json
{
"extends": "@tsconfig/node18/tsconfig.json"
}
```
### [[tsconfig.json]]の設定
[[JavaScript]]ファイルは`lib`配下に格納したいので、[[outDir]]と[[include (tsconfig)|include]]を設定する。
`mimizou-cli/tsconfig.json`
```json
{
"extends": "@tsconfig/node18/tsconfig.json",
"include": ["src/**/*"],
"compilerOptions": {
"lib": ["es2022", "dom"],
"outDir": "lib"
}
}
```
> [!caution]
> 参照元のサイトでは[[lib (tsconfig)|lib]]に`dom`が追加されていなかった (注意喚起はされているけど)
### コードの変更
実行側、`mimizou-cli`の`index.js`を`index.ts`に変更し、`src`ディレクトリ配下に移動する。
`mimizou-cli/src/index.ts`
```ts
import { hello } from "@tadashi-aikawa/mimizou-lib-test";
console.log(hello("world"));
```
[[package.json]]に`scripts`を追加。`dependencies`の相対パスも調整する。
`mimizou-cli/package.json`
```json
{
"scripts": {
"build": "tsc"
},
"dependencies": {
"@tadashi-aikawa/mimizou-lib-test": "file:../../mimizou-libtest"
},
"devDependencies": {
"@tsconfig/node18": "^1.0.1",
"typescript": "^4.9.5"
}
}
```
ビルドするとエラーが出る。
```console
$ npm run build
src/index.ts:1:23 - error TS7016: Could not find a declaration file for module '@tadashi-aikawa/mimizou-lib-test'. 'C:/Users/syoum/tmp/npm-sandbox/mimizou-libtest/index.js' implicitly has an 'any' type.
1 import { hello } from "@tadashi-aikawa/mimizou-lib-test";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
```
`mimizou-libtest`には型定義がないので、[[TypeScript]]としてはimportできないであろう。
## ライブラリプロジェクトの[[TypeScript]]化
- エントリポイントは[[package.json]]の`main`
- デフォルト値は`index.js`
- 型定義は[[package.json]]の`types`
### [[TypeScript]]と[[tsconfig.json]]の準備
[[TypeScript]]と[[tsconfig.json]]のベースをインストール。
```console
npm install -D typescript @tsconfig/node18
```
[[tsconfig.json]]は`mimizou-cli`をベースに以下の変更を加える。
- [[lib (tsconfig)|lib]]から`dom`を削除
- [[console.log]]は不要なため
- [[declaration]]に`true`を指定
- 型定義ファイルを生成するため
`mimizou-libtest/tsconfig.json`
```json
{
"extends": "@tsconfig/node18/tsconfig.json",
"include": ["src/**/*"],
"compilerOptions": {
"outDir": "lib",
"declaration": true
},
}
```
### コードの変更
[[JavaScript]]ファイルを[[TypeScript]]ファイルに。
`mimizou-libtest/src/index.ts`
```ts
export const hello = (name: string): string => "Hello, " + name + "!";
```
### ビルド
`mimizou-libtest/package.json`
```json
{
"name": "@tadashi-aikawa/mimizou-lib-test",
"scripts": {
"build": "tsc"
},
"devDependencies": {
"@tsconfig/node18": "^1.0.1",
"typescript": "^4.9.5"
}
}
```
ビルドする。
```console
npm run build
```
成功すると、`lib`ディレクトリが作成され、`index.d.ts`と`index.js`が生成されていることを確認できる。
`mimizou-libtest/lib/index.js`
```json
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.hello = void 0;
const hello = (name) => "Hello, " + name + "!";
exports.hello = hello;
```
`mimizou-libtest/lib/index.d.ts`
```ts
export declare const hello: (name: string) => string;
```
最後に、それらをエントリポイントと設定するため、[[package.json]]の`main`と`types`を更新する。また、利用側で必要なもののみを提供するため、[[files (npm)|files]]に`lib`のみを指定する。
`mimizou-libtest/package.json`
```json
{
"name": "@tadashi-aikawa/mimizou-lib-test",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"files": ["lib"],
"scripts": {
"build": "tsc"
},
"devDependencies": {
"@tsconfig/node18": "^1.0.1",
"typescript": "^4.9.5"
}
}
```
## ライブラリ利用プロジェクトでリトライ
ライブラリ利用プロジェクトに移動して、もう一度インストール。
```console
cd ../mimizou-cli
npm i ../mimizou-libtest
```
ビルドをすると成功するはず。
```console
npm run build
```
実行して動けばOK!
```console
$ node lib/index.js
Hello world!
```