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

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

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からいただきました。最初に思いついた人すごいですね。