引数に応じて親クラスを切り替えたいことがあって調べて、Dynamic super classes (extends) in ES6 – MikeDoesWeb が出てきたので試した。
おそらく私はmix-inみたいなことをしたかったのだと思う。
サンプルコードとそれのテスト(使い方の例になると思う)はGitHubに置いた。
github.com
解決法の解説/概要
クラスを直接定義するのではなく、関数スコープ内で定義することで解決していた。
実際に私がやりたかったのはNode.jsで動くならfs
を使うクラスを継承して、ブラウザで動くならBrowserFS
を使うクラスを継承したかった。
外からみると同じAPIにしたかったので、環境か引数によって必要なバックエンドのクラスを切り替えてテストしたかった。
以下GitHubに置いた解決策の抜粋。
export class FS {
constructor(config){
}
}
export class BrowserFS {
constructor(config){
}
}
export class DefaultClass {
constructor(config){
}
};
const Dynamic = function(config = {}){
if(!new.target){
throw "Uncaught TypeError: Class constructor Dynamic cannot be invoked without 'new'";
}
if(config.backend === 'fs'){
class Dynamic extends FS {
constructor(config){
}
};
return new Dynamic(config);
}
if(config.backend === 'browserfs'){
class Dynamic extends BrowserFS {
constructor(config){
}
};
return new Dynamic(config);
}
return new DefaultClass(config);
};
export default Dynamic;
es6-dynamic-class-extends/dynamic.js at master · peccu/es6-dynamic-class-extends · GitHub
使用法はテストコードでイメージできるかと。
(Jest利用、同じく抜粋)
Dynamic
はクラスではなく関数なので、instanceof Dynamic
はfalseとなる。
import {default as Dynamic, FS, BrowserFS, DefaultClass} from './dynamic';
describe('Dynamically switching parent class', () => {
test('non specified class', () => {
let target = new Dynamic();
expect(target).toBeInstanceOf(DefaultClass);
});
test('extends FS', () => {
let target = new Dynamic({backend: 'fs'});
expect(target).toBeInstanceOf(FS);
});
test('extends BrowserFS', () => {
let target = new Dynamic({backend: 'browserfs'});
expect(target).toBeInstanceOf(BrowserFS);
});
});
es6-dynamic-class-extends/dynamic.test.js at master · peccu/es6-dynamic-class-extends · GitHub
c.f.
github.com
environment
{
"presets": ["@babel/preset-env"],
"plugins": [
[
"@babel/plugin-transform-runtime",
{
"regenerator": true
}
]
]
}
...
"scripts": {
"test": "jest"
},
"devDependencies": {
"@babel/core": "^7.2.2",
"@babel/plugin-transform-runtime": "^7.2.0",
"@babel/preset-env": "^7.2.3",
"@babel/runtime": "^7.2.0",
"babel-core": "^7.0.0-bridge.0",
"babel-jest": "^23.6.0",
"jest": "^23.6.0"
},
...