Usage with typescript?
xaviergonz opened this issue · comments
Given this base code:
export class CounterStore {
@observable counter: number = 0;
}
export class AppStore {
@observable readonly counter: CounterStore = new CounterStore();
}
I tried:
const appStore: AppStore = new remotedev(AppStore)();
export default appStore;
But it gives:
Uncaught TypeError: Cannot call a class as a function
So then I tried decorating the AppStore class itself as:
@remotedev
export class AppStore {
@observable readonly counter: CounterStore = new CounterStore();
}
const appStore: = new AppStore();
export default appStore;
And then it gives
Uncaught TypeError: Class constructor AppStore cannot be invoked without 'new' at new store (C:\VSProjects\SkirmishJs\server\node_modules\mobx-remotedev\lib\dev.js:48:67)
Is there a way to make it work using typescript classes?
PS: typescript types for the library would be cool too :)
That's a shame to confess, but I still didn't get to use TypeScript (just a bit of Flow). A pr to add types for the library would be much appreciated.
yes we need this feature
It's weird, on my side if I try
@remotedev({ global: true })
class AppState {
@observable timer = 0;
@action
bumpTimer() {
this.timer++;
}
}
export default AppState;
....
const appState = new AppState();
It doesnt trigger an error but simply doesnt let me debug at all
@azukaar do you have the extension installed?
@zalmoxisus yeah yeah I do,, and it tells me "No store found. Make sure to follow the instructions.". Even AFTER actions are indeed triggered
@azukaar @yann-stepienik-cko see the notes about environment. By default it works only when process.env.NODE_ENV === 'development'
.
If that's not the case, please share a simple repo I could run. I tried your snippet and it works as expected.
@zalmoxisus I've been able to make it work by adding a NODE_ENV thanks !
I think everything work now.
@xaviergonz if you're still unable to use the plugin with TS feel free to chekcout my code !
Here is the repo : https://github.com/azukaar/react-typescript-mobx-webpack
FYI I reproduced this when TypeScript target language is es6, but not es5.
@WearyMonkey seems like the class is not extended (since it's in commonjs/es5 from inside the lib). You can try to do it on your side like here. Where spy
will be imported from mobx-remotedev/lib/spy
.
You can also create a decorator like here.
I'm experiencing this issue in a Babel setup including transform-class-properties
if that's relevant.
import { observable, action } from 'mobx'
import remotedev from 'mobx-remotedev/lib/dev'
@remotedev({ name: 'example', global: true })
class ExampleStore {
@observable example = ''
@action setExample = text => {
this.example = text
}
}
export default new ExampleStore()
Mobx itself works fine, but upon adding that remotedev
decorator I get Uncaught TypeError: Class constructor ExampleStore cannot be invoked without 'new'
.
For what it's worth I just added a mobx-remotedev.d.ts
file to local @types
folder in the project root (i.e. not node_modules/@types
) with the following content:
declare module 'mobx-remotedev' {
export default function<T>(store: T): T
}
I also added the following lines to tsconfig.json
:
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"*": ["@types/*"]
}
}
}
This is obviously not the full declaration, but it's enough in my case. And it also works with React Native debugger which is just awesome.
HI @zalmoxisus, i absolutely hate Redux but i love their devtool. I also love Mobx and hate their devtools.
to make matters complicated, i love Typescript but i also hate Babel. is there a way for me to enjoy this wonderful package without using babel at all?
@BlackFenix2 yes, we just need index.d.ts
file in our package root with definitions, which typescript will pick by default when you import our package. If someone can submit a PR adding it I'd publish a new version to npm with it. Could add just export default function<T>(store: T): T
as @baygeldin suggested, but not sure it will work for all cases (store can be a class or an object or probably other types which can be observable).
@zalmoxisus i made a PR adding index.d.ts. its minimal but it should work.
Thanks @BlackFenix2! I published it as mobx-remotedev@0.3.1
.
Thanks @BlackFenix2! I published it as
mobx-remotedev@0.3.1
.
NP, ill give it a try now!
i might make another PR to add more detailed Typescript definitions.
terribly sorry, but i should of declared export default function<T>(store: T, config:object): T
instead of export default function<T>(store: T): T
,
i forgot about the config object passed in as a second argument. ill get another PR with the correct Type definition ready
NP, thanks for working on this @BlackFenix2!
i submitted another PR to address the index.d.ts bug #38
i also included a basic RemoteDevConfig object definition.
Thanks @BlackFenix2! It's published as 0.3.2
.
I tried out the new version, the TypeDefinitions are there but i am still getting the error:
TypeError: Class constructor RootStore cannot be invoked without 'new'
this is my base code:
import remotedev from 'mobx-remotedev';
// import stores
import FruitStore from './fruitStore';
import RouteStore from './routeStore';
import ShowStore from './showStore';
import TodoStore from './todoStore';
class RootStore {
TodoStore = new TodoStore();
ShowStore = new ShowStore();
FruitStore = new FruitStore();
RouteStore = new RouteStore();
}
export default remotedev(RootStore, { global: true });
and this is where i add the stores to my provider:
import createBrowserHistory from 'history/createBrowserHistory';
import { Provider as MobxProvider } from 'mobx-react';
import { RouterStore, syncHistoryWithStore } from 'mobx-react-router';
import * as React from 'react';
import { Router } from 'react-router';
import RootStore from 'src/state/stores';
import Body from './Body';
import Footer from './Footer';
import Header from './Header';
// set up Mobx Routing Store
const browserHistory = createBrowserHistory();
const RoutingStore = new RouterStore();
const rootStore = new RootStore();
const history = syncHistoryWithStore(browserHistory, RoutingStore);
class App extends React.Component {
render() {
return (
<MobxProvider {...rootStore} routing={RoutingStore}>
<Router history={history}>
<AppLayout />
</Router>
</MobxProvider>
);
}
}
const AppLayout = () => (
<React.Fragment>
<Header />
<Body />
<Footer />
</React.Fragment>
);
export default App;
and this is the line that throws an error for me in lib/dev.js:
var _this = _possibleConstructorReturn(this, _store2.call.apply(_store2, [this].concat(args)));
i may be a little stumped at this point. im going to try and use the repo recommend by @azukaar
https://github.com/azukaar/react-typescript-mobx-webpack
https://github.com/azukaar/react-typescript-mobx-webpack
so far all i found out is that i need the babel preset "presets": ["es2015"]
to get the Error to disappear and enable the devtools.
now we got to figure out a way to get this working with zero babel.
@BlackFenix2 does TS use that definition we added? Maybe it should be in lib
folder?
@zalmoxisus the default function is getting the type definitons below.
(alias) remotedev<typeof TodoStore>(store: typeof TodoStore, config?: RemoteDevConfig): typeof TodoStore (+1 overload) import remotedev
export const test = remotedev(TodoStore, { onlyActions: true });
i know the error happens at line 50 in dev.js when the call method is invoked
for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
=>var _this = _possibleConstructorReturn(this, _store2.call.apply(_store2, [this].concat(args)));
(0, _spy2.default)(_this, config);
return _this;
since the lib directory is compiled we might be able to use Typescript to compile the files rather than Babel, like in this fork:
https://github.com/hlhr202/mobx-remotedev
it is behind your main branch. but i can attempt to add this to my fork and test the package locally. ill investigate.
Almost forgot to mention, if i use this .babelrc config and tsconfig.json remotedev works perfectly for me
.babelrc
{ "presets": ["@babel/env", "@babel/typescript"], "plugins": [ "@babel/plugin-syntax-dynamic-import", "@babel/plugin-transform-runtime" ] }
tsconfig.json
{
"compilerOptions": {
// compile JSX syntax to JS
"jsx": "react",
// use latest ES version including proposed features
"module": "esnext",
"target": "esnext",
// targets node
"moduleResolution": "node",
// force case-sensitive imports to avoid compile-time errors
"forceConsistentCasingInFileNames": true,
// allows default import of modules without default exports, shorthand for import * as item from 'module'
"esModuleInterop": true,
//Allow decorators
"experimentalDecorators": true,
//needed for mmlpx
"emitDecoratorMetadata": true,
//remove unneeded comments
"removeComments": true,
// ALIAS src path
"baseUrl": "./",
"paths": {
"src/*": ["src/*"]
}
},
//testing support for mobx-remotedev package
"awesomeTypescriptLoaderOptions": {
"useBabel": true,
//add Babel 7
"babelCore": "@babel/core"
}
}
i have it all working on my github repo https://github.com/BlackFenix2/Portfolio
the live site is react.erniefrancisiv.com/todo .redux devtools wont work here since production, but feel free to fork my repo and check for yourself.
All i figued out is that dev.js bugs out when i do not transpose my classes to fuctions with Babel.
line:
console.log('Class or fuction:', _getPrototypeOf(store));
_this = _possibleConstructorReturn(
this,
(_getPrototypeOf2 = _getPrototypeOf(store)).call.apply(
_getPrototypeOf2,
[this].concat(args)
)
);
with babel 7:
Class or fuction: ƒ TodoStore() {
(0, _classCallCheck2.default)(this, TodoStore);
this.todoList = [];
this.testState = 'test';
}
without babel:
Class or fuction: class TodoStore {
constructor() {
this.todoList = [];
this.testState = 'test';
}
get completedTasks() {
return this.todoList.filter(todo => todo.isComplete).length…
this PR #40 should fix the typescript issues.
Thanks for fixing it @BlackFenix2! I also added you as a collaborator for this repo.
Please update docs how to use it with typescript and how to export