zalmoxisus / mobx-remotedev

MobX DevTools extension

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

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.

#37

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