7
7

More than 3 years have passed since last update.

【TypeScript】よく使う処理を複数のプロジェクトで使い回す

Last updated at Posted at 2020-03-29

環境

  • npm: 6.4.1
  • typescript: 3.8.3

使いどころ

JavaScript(TypeScript)を書いているときに「こういうメソッドがあったら便利なのにな」と感じることがしばしばあると思います。例えば以下のような

.ts
// 配列の最初の要素を取得(自分で定義しないと使えない)
[1, 2, 4].first() // 1
[].first()        // undefined

// 1個次の要素を取得(自分で定義しないと使えない)
[1, 2, 4].nextOf(2) // 4
[1, 2, 4].nextOf(3) // undefined

もちろん以下のようにprototypeを操作したりライブラリを導入したりすることで使えるようにはなりますが、

Array.prototype.first = function<T>(): T | undefined {
  const arr = this as Array<T>
  return arr.length > 0 ? arr[0] : undefined
}

例えば複数のアプリを作っているとして、各アプリ内で毎回こういった定義をするのかということを考えると、できれば別プロジェクトに切り出したいところではあります。
ということで色々と試行錯誤したので備忘録を兼ねて投稿

概要

  • 共通処理専用のプロジェクトを作成する
  • それをGitHubにアップする
  • 共通処理利用側プロジェクトでnpm install 上記GitHubリポジトリのURL

手順

共通処理プロジェクトの作成

※ TypeScriptでちゃんと型が参照できるようにするためにその手順も含んでいます。

TypeScriptをインストール

npm install -D typescript

tsconfig.json を作成

./node_modules/.bin/tsc --init
以下のコンフィグで動作を確認済みです。

tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "commonjs",
    "strict": true,
    "declaration": true, // .d.ts ファイルが生成されるようにする
    "outDir": "dist" // ビルド後ファイル生成先ディレクトリ名
  }
}

共通処理を作成

my-array-extensions.ts
// 拡張メソッドの型の宣言をします。
// これを書くことで、ビルド時に型定義ファイル(aaa.d.ts)が作成され、
// 共通処理利用側プロジェクトのtypescriptでこの関数を参照できるようになります
declare global {
  interface Array<T> {
    nextOf: (item: T) => T | undefined
  }
}

export default function() {
  // 関数'nextOf'の実装を定義します。
  // たとえ関数が宣言されていても、この行を通らないと、
  // 実行時に '~~~.nextOf is not function' としてエラーになります。
  Array.prototype.nextOf = function<T>(item: T) {
    const arr = this as Array<T>
    const index = arr.indexOf(item)
    return index === -1 || index >= arr.length - 1 ? undefined : arr[index + 1]
  }
}
index.ts
// exportしないと .d.ts ファイルが作成されず、他のプロジェクトから nextOf の定義を参照できない
export * from './my-array-extensions'

// 上記のファイルで定義した関数を実行し、prototypeに関数を代入します。
// 他のプロジェクトから実行されるのはpackage.jsonのmainに記述したビルド後のファイルなので、
// そのファイルの中でprototypeへの代入処理が実行されないと処理が定義されません。
// myArrayExtensionsの名前は何でも可
import myArrayExtensions from './my-array-extensions'
myArrayExtensions()

package.json を作成

npm init -y

main, build, postinstallの行が重要です。

package.json
{
  "name": /* 適当なパッケージ名 */,
  "version": "1.0.0",
  "description": "",

  // 他のプロジェクトからの参照時にはこれが実行されます。
  "main": "dist/index.js",

  "dependencies": {
    "typescript": "^3.8.3"
  },
  "devDependencies": {},
  "scripts": {

    // tscの実行により .ts ファイルが .js ファイルに変換されます。
    "build": "tsc",

    // postinstallという名前は他のプロジェクトで `npm install 共通処理のプロジェクト` を
    // したときに自動的に実行されるコマンドです。
    // tsc(TypeScriptのトンラスパイル)を実行し、tsconfig.jsonに記載した./distディレクトリにトランスパイル後ファイルを出力します。
    "postinstall": "npm run build"

  },
  "author": "",
  "license": "MIT"
}

GitHubにアップロード

リポジトリを作ってアップロードします(詳細割愛)。gitignoreの中身はこちらです。

.gitignore
/node_modules
/dist

共通処理利用側プロジェクトでの準備

インストール

npm install https://github.com/リポジトリのURL.git

package.json
{
  /* 略 */

  "dependencies": {
    /* 共通処理のパッケージ名 */: "git+https://github.com/GitHubのリポジトリのURL.git"
  }

  /* 略 */
}

インポート

あとは利用側の方のプロジェクトでimportすれば利用可能です。

利用側プロジェクトのソース.ts
console.log([1, 2, 4].nextOf(2)) // TypeError: [1, 2, 4].nextOf is not a function

import '共通処理のパッケージ名' // import後に利用可能

console.log([1, 2, 4].nextOf(2)) // 4

共通処理プロジェクトで更新があった場合

GitHubのリポジトリにpushしたあと、利用側プロジェクトで npm install 共通処理プロジェクトのパッケージ名 で更新します。

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