Cover image for TypeScriptでreact-nativeのPlatform-specific extensionsを型安心にする
typescriptreact-native

TypeScriptでreact-nativeのPlatform-specific extensionsを型安心にする

May 21, 2019

3 min read

mitsuruogMitsuru Ogawa

TypeScript の小ネタです。

react-native にはPlatform-specific extensionsという仕組みがあります。

これはファイルを拡張子を使って各プラットフォーム(Android/iOS)向けにモジュール参照先を切り替える仕組みです。

例えば次のように各プラットフォームごとにカスタマイズされたモジュールを作成したとします。

BigButton.android.ts;
BigButton.ios.ts;

これを利用するときは次のように呼び出すことができます。

import BigButton from "./BigButton";

ところが、これを TypeScript でやろうとした場合、モジュール参照先にファイルが存在しないためエラーとなります。

// TS2307: Cannot find module './BigButton'.
import BigButton from "./BigButton";

今日はこれを解消する方法の紹介です。

.d.ts を作成して回避する

回避方法としては、次のようなBigButtonの型定義ファイルを作成するだけです。

// BigButton.d.ts
import * as ios from "./BigButton.ios";
import * as android from "./BigButton.ios";

declare var _test: typeof ios;
declare var _test: typeof android;

// ここでモジュールの型情報を提供する
export * from "./BigButton.ios";

これでコンパイルエラーは消えました。

この仕組みで興味深いことは、_testの Type を再割り当てすることで、各プラットフォームのコードの差異を検知することができることです。

試しにモジュールの中身を違うものに変えてみたところ、次のように差異があることを検知することができました。

TS2403: Subsequent variable declarations must have the same type. Variable '_test' must be of type 'typeof import("BigButton.ios")', but here has type 'typeof import("BigButton.android")'.

まとめ

TypeScript のコンパイラの方でサポートして欲しいという要望があったようですがクローズされてしまったようです。 当分の間は上で紹介した方法で回避するしかなさそうです。

今回のトリックも上の Issue からいただきました。最初に思いついた人すごいですね。