ExpoのConfig Pluginを独自で作成する場合コードはJavaScriptで記述できますが、コード量が増えてきたり複雑な処理を行うPluginを作成したい場合、型のサポートの恩恵を受けられるためTypeScriptを利用するのがおすすめです。
この記事ではConfig PluginをTypeScriptで作成するための設定やテストの設定について説明します。
記載の内容は以下の公式のドキュメントを元にしています。
 Config Plugin用のtsconfig.json
Config Plugin用のtsconfig.jsonConfig PluginはNode.js(LTS)で実行されるため、TypeScriptでコードを書いた場合Node.jsで実行可能なJavaScriptにTranspileする必要があります。
React NativeアプリのソースコードもTypeScriptで記述することができますが、トランスパイルするターゲットがConfig Pluginとは異なる(ES6やJSXがサポートされている)ため、同じtsconfig.jsonを共有することはできません。そのためConfig Plugin用に別途tsconfig.jsonを用意する必要があります。
 expo-module-scripts
expo-module-scriptsexpoがユーティリティとして用意しているexpo-module-scriptsというライブラリが存在します。これはExpoのモジュールやSDKが共通で利用しているスクリプトや設定をまとめたものになります。
Config Plugin用のtsconfig.jsonを用意してくれたり、Pluginのビルドを行うためのコマンドツール等を提供してくれます。利用する場合はインストールしておきます。
yarn add --dev expo-module-scripts
必ずしもこれを利用する必要はなく、もしも使わない場合は独自でtsconfig.jsonの記述やビルド用のスクリプトを用意する形になります。
 フォルダ構成
フォルダ構成Config Plugin関連のファイルはすべてpluginフォルダに配置します。expo-module-scriptsのトランスパイル用のスクリプトがこの名前のフォルダ名であることを前提としているため、名前をそれに合わせます。別の名前にしても問題ありませんが、その場合はビルド用のスクリプトを自身で用意する必要があります。
tsconfig.jsonはplugin/tsconfig.jsonに配置します。expo-module-scriptsが用意したtsconfigを継承しています。
{
  "extends": "expo-module-scripts/tsconfig.plugin",
  "compilerOptions": {
    "outDir": "build",
    "rootDir": "src"
  },
  "include": ["./src"],
  "exclude": ["**/__mocks__/*", "**/__tests__/*"]
}
ソースコードはplugin/srcに配置し、トランスパイルされたコードはplugin/buildに吐かれます。
 Config Pluginを配置
Config Pluginを配置実際にTypeScriptで書かれたConfig Pluginをsrc配下に配置します。
plugin/src/withExample.ts
import { ConfigPlugin } from "@expo/config-plugins"
type Props = { name: string }
export const withExample: ConfigPlugin<Props> = (config, props) => {
  console.log("withExample()")
  config.name = props.name
  return config
}
plugin/src/index.ts
import { ConfigPlugin } from "@expo/config-plugins"
import { withExample } from "./withExample"
const withPlugins: ConfigPlugin = config => {
  config = withExample(config, { name: "hello" })
  return config
}
export default withPlugins
この状態で以下のコマンドを実行するとplugin/build配下にトランスパイルされたjsファイルが生成されます。
EXPO_NONINTERACTIVE=1 npx expo-module build plugin
EXPO_NONINTERACTIVE=1を指定しているのは指定しないとwatchモードになるためです。逆にwatchする場合はこれを外せばOKです。
PluginをPrebuild時に実行するようにするには、app.json(またはapp.config.js)にpluginsの設定を追加します。
{
  "expo": {
    ...
    "plugins": ["./plugin/build"]
  }
}
 jestでのテストの設定
jestでのテストの設定jestでテストができるようするにはまずjestをインストールし
yarn add --dev jest
plugin/jest.config.jsを配置します。
module.exports = {
  ...require("expo-module-scripts/jest-preset-plugin"),
  testRegex: "(/__tests__/.*|(\\.|/)(test|spec))\\.[jt]sx?$",
}
ここでもexpo-module-scriptsが提供するjestの設定を利用しています。testRegexを指定し直しているのはsample.test.tsのような形式で配置した場合にテスト対象と認識されないためです。このあたりは自身の利用したい形式に合わせて設定を変えればよいと思います。
実際にテストファイルを配置し
plugin/src/withExample.test.ts
import { withExample } from "./withExample"
describe("withExample", () => {
  it("sets name in config", () => {
    const config = {}
    const result = withExample(config as any, { name: "hello" })
    expect(result.name).toBe("hello")
  })
})
以下のコマンドでテストを実行します。
npx expo-module test plugin
 スクリプトをpackage.jsonに追加
スクリプトをpackage.jsonに追加ビルドやテスト時に利用するコマンドはpackage.jsonに以下のように設定しておくとよいです。
"scripts": {
  ...
  "plugin:build": "EXPO_NONINTERACTIVE=1 expo-module build plugin",
  "plugin:watch": "expo-module build plugin",
  "plugin:test": "expo-module test plugin",
}
 Config Pluginの実行を手元で検証する
Config Pluginの実行を手元で検証するConfig Pluginが実際に問題なく動作するかどうかをローカルで確かめるにはexpo prebuildを実行します。
expo prebuild
実行後、Config Pluginで設定した内容がPrebuild時に実際に反映されているかを確認します。
 実際の設定サンプル
実際の設定サンプル今回おこなった設定を反映した実際のプロジェクトサンプルを以下で確認できます。
https://github.com/gaishimo/rn-expo-sandbox/tree/config-plugin-dev