Last Modified:
#NativeScript のプラグインを #TypeScript で書くときのベストプラクティス
$ git clone https://github.com/NativeScript/nativescript-plugin-seed ./nativescript-myplugin
$ cd ./nativescript-myplugin/src
$ npm run postclone
という感じでひな形を作ると、 package.jsonが
"main": "myplugin",
"typings": "index.d.ts",
となっていて、実装をmyplugin.${platform}.tsから、型定義をindex.d.tsから読み込むようになってる。 これ、普通に書いてると
- 同じ型定義を複数回書かないといけなくなる
- 型チェックとビルドが上手くできない
のどちらかに陥ってしまう(実際にやってみると分かるんだけど、言葉でうまく説明できない)。 例えば
- index.d.tsで
export interface MyPlugin {}
::TS2693: 'MyPlugin' only refers to a type, but is being used as a value here.
でビルドができない - index.d.tsで
interface MyPluginInterface {}; export declare class MyPlugin implements MyPluginInterface {}
:: (myplugin.${platform}.tsを見るので)ビルドはできるが(index.d.tsを見るので)型チェックができない - myplugin.common.d.tsをindex.d.tsだということにする :: インターフェイス以外のprivateな定義なども(プラグインの場合はplatform依存であることが多いので)出てきてしまうのが嫌
忘れた
:: ビルドも型チェックもできるが、myplugin.${platform}.ts側で実装の強制ができない- 他色々
解決
それで思いついたのが、index.d.tsではクラスとして定義しつつ、myplugin.${platform}.tsでそれをインターフェイスとして使うと言う方法。
export declare class MyPlugin {
myplugin();
}
import { MyPlugin as MyPluginInterface } from './index';
export class MyPlugin implements MyPluginInterface {
myplugin() {
}
}
こうすることでビルドが通り、型チェックもでき、未実装の場合にエラーにできる。 ポイントは、
- どうしても型定義と実装が同じ名前になってしまうので、
as
でリネームすること class
として定義しておいてextends
ではなくimplements
すること
です。