Skip to content

Instantly share code, notes, and snippets.

@oakfang
Created January 10, 2019 12:45
Show Gist options
  • Save oakfang/3c5b620806aa4aabcf551155197a5c03 to your computer and use it in GitHub Desktop.
Save oakfang/3c5b620806aa4aabcf551155197a5c03 to your computer and use it in GitHub Desktop.
Typesafe inject
import React, { Component } from "react";
import { observable, action } from "mobx";
import { inject, Provider, observer } from "mobx-react";
import "./App.css";
declare module "mobx-react" {
type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
type Diff<MasterObject extends SubObject, SubObject extends Object> = Omit<
MasterObject,
keyof SubObject
> &
Partial<MasterObject>;
interface WrappedComponent<I, P extends I>
extends React.ComponentClass<P, any> {
new (props: I, context?: any): Component<I, any, any>;
}
export function inject<IRootStore, StoreProps>(
mapStoreToProps: (rootStore: IRootStore) => StoreProps
): <ComponentProps extends StoreProps>(
target: IReactComponent<ComponentProps>
) => WrappedComponent<Diff<ComponentProps, StoreProps>, ComponentProps>;
}
class Counter {
@observable count: number = 0;
@action.bound inc() {
this.count++;
}
@action dec = () => this.count--;
}
interface Stores {
countStore: Counter;
}
@observer
class CountComponent extends Component<{ countStore: Counter }> {
render() {
return (
<>
<p>{this.props.countStore.count}</p>
<button onClick={this.props.countStore.inc}>+</button>
</>
);
}
}
const CountComponent2 = inject((stores: Stores) => ({
countStore: stores.countStore
}))(CountComponent);
const countStore = new Counter();
class App extends Component {
render() {
return (
<div className="App">
<header className="App-header">
<Provider countStore={countStore}>
{/* <CountComponent /> */}
<CountComponent2 />
</Provider>
</header>
</div>
);
}
}
export default App;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment