ひびのログ

日々ではないけどログを出力していくブログ

TypeScript で動的にメソッドを追加する

JavaScriptでは、prototypeに適当に代入してあげればメソッドやプロパティの追加ができますが、 型という楽園を手に入れた TypeScript では簡単にはできません。

でもどうにかこうにかやる方法があったので、ググって色々試した結果を載せておきます。

ちなみに、現在作成中のこちらのソースで使っています。

github.com

やってみる

Stringにメソッドを生やしたいと思います。 const methodName = "methodName"が定義されている前提です。

ひとまずJSと同様に

String.prototype[methodName] = function (): void {}
// => error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.

当たり前にエラーです。 string型でインデックスアクセスできませんよーとのことです。

インターフェースに定義してみる

interface String {
    [index: string]: Function;
}
String.prototype[methodName] = function (): void {}
// => error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.

インターフェースを定義してみましたが同じエラーが。 ちゃんと型定義ができていないみたいです。

ちなみに、indexkeyとかmethodNameとかにしてもダメでした。

ならばprototypeに直接

interface String.prototype {
    [index: string]: Function;
}
String.prototype[methodName] = function (): void {}
// => error TS1005: '{' expected.

そもそもクラスじゃないのでダメですね。

型に直接いれよう

interface string {
    [index: string]: Function;
}
String.prototype[methodName] = function (): void {}
// => error TS2427: Interface name cannot be 'string'.
//    error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.

インターフェースにはプリミティブ型は直接定義できないみたいです。

prototypeobject型なので

interface Object {
    [index: string]: Function;
}
String.prototype[methodName] = function (): void {}
// => error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.

こちらもinterface Stringと同じエラー。

とりあえず型のほうも試してみる

interface object {
    [index: string]: Function;
}
String.prototype[methodName] = function (): void {}
// => error TS2427: Interface name cannot be 'object'.
//    error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'.

やっぱりだめでした。

そして伝説へ……

(String.prototype as any)[methodName] = function (): void {}

これでコンパイルが通りました!

要するに、anyにキャストしてからメソッドを追加しています。

アディショナルタイム

interface String {
    [index: string]: Function;
}
(String.prototype as String)[methodName] = function (): void {}
// => error TS2352: Type 'String' cannot be converted to type 'String'.
//    error TS2352: Type 'String' cannot be converted to type 'String'. Index signature is missing in type 'String'.

Stringにしてみてもいけるかなーって思ったんですがダメでした……

所感

型を守りたかったんですが、最後はキャストで無理やりという結果に。

他にいいやり方があれば教えていただければ幸いです。