Last active
June 15, 2019 23:47
-
-
Save vonovak/29c972c6aa9efbb7d63a6853d021fba9 to your computer and use it in GitHub Desktop.
using flowtype with @Inject from 'mobx-react'
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import type File from "File"; | |
import type FileService from "FileService"; | |
type FileDetailProps = { | |
file: File | |
}; | |
class FileDetail extends React.Component<FileDetailProps> { | |
render() { | |
// remove the file prop and flow will complain! | |
return <FileDownload file={this.props.file} />; | |
} | |
} | |
type InjectedProps = { | |
fileService: FileService | |
}; | |
// for older flow versions | |
function typedInject<Props>( | |
WrappedComponent: React.ComponentType<InjectedProps & Props> | |
): React.ComponentType<Props> { | |
return inject("fileService")(WrappedComponent); | |
} | |
// for flow version > 60 (or so) | |
function typedInject<Props: {}>( | |
WrappedComponent: React.ComponentType<Props> | |
): React.ComponentType<$Diff<Props, InjectedProps>> { | |
return inject("fileService")(WrappedComponent); | |
} | |
// NOTE you can spread types from InjectedProps to reuse them | |
type FileDownloadProps = { | |
file: File, | |
...$Exact<InjectedProps> | |
}; | |
//NOTE using | |
//@typedInject | |
//class FileDownload extends ... will NOT work - why? (maybe related to `esproposal.decorators=ignore` in .flowconfig) | |
const FileDownload = typedInject( | |
class FileDownload extends React.Component<FileDownloadProps> { | |
download = () => { | |
// flow will happily access both file and fileService props! | |
this.props.fileService.downloadFile(this.props.file); | |
// flow will complain: [flow] property `foo` (Property not found in object type) | |
this.props.foo.bar(); | |
}; | |
render() { | |
return <Button onPress={this.download}>download file!</Button>; | |
} | |
} | |
); |
I'm using the following approach in some of my apps:
I'm pretty sure your solutions are way smarter than this but I'm I wanted to share my finding, maybe someone else is interested.
P.S.: the Stores
type is defined this way:
/* @flow */
import CoreStore from "../stores/Core";
import SessionStore from "../stores/Session";
import ConfigurationStore from "../stores/Configuration";
export type Stores = {
core: CoreStore,
session: SessionStore,
configuration: ConfigurationStore
};
@Gvozd 's method works for me. It is a positive not to have to write extra code in every component.
@coremessage the modification you suggested results in the original flow error about missing injected props again for me. Having a flow ignore comment doesn't seem to bad though.
I prefer explicit way of typing inject. I described it here: facebook/flow#6777 (comment)
The proposed way has several advantages:
- It supports covariant (readonly) props.
- It supports optional props and defaultProps.
- You are not required to mark optional any injected props.
- It allows you to inject subtypes instead of props' type;
- It allows you to inject only small part of store, not entire store.
- It has exhaustive type checks. So you can not inject any props that are not defined in component props. You should pass to component all mandatory props that are not injected, not marked optional and not default. You can not pass prop to component that has been already injected. Also you can not pass any props that is not defined in component props.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's what I've done.
I import all our stores in the libdef file.