ググって見つかる記事を参考にすると、interface + prototypeでメソッドの宣言と定義を2回に分けなければならず面倒。
けど、こんな感じでかけば定義と宣言を同時にできて楽。
適当なファイルにmixin関数を用意する
function mixin(base: { prototype: any[] }, derived: object) {
Object.getOwnPropertyNames(derived).forEach((propertyName) => {
Object.defineProperty(base.prototype, propertyName as (keyof (typeof derived)), {
// @ts-ignore
value: derived[propertyName],
writable: true
});
});
}
拡張部分
Arrayクラスに対してget, head, lastを定義する例。
prototype.ts
export {}
type Super<T> = Array<T>;
type ArrayExClass = typeof ArrayEx;
declare global {
interface Array<T> extends ArrayExClass {}
}
const ArrayEx = {
get: function <T>(this: Super<T>, index: number): T {
return this[index];
},
head: function <T>(this: Super<T>): T {
return this.get(0);
},
last: function <T>(this: Super<T>): T {
return this.get(this.length - 1);
},
}
mixin(Array, ArrayEx)
- prototypeに1個1個代入していくパターンに比べて、使いまわしが聞く。そのためmixinのような動きに近いこともできる。
- self type annotationみたいな制限もthisの型を調整すればできそう。