I've came into a problem where I have to re-type / re-define repeating types in my store / view / components files i.e. Think a view that takes in some store value and has a function that alters that value and this function is passed down to a component.
There is a lot of type re-usability happening here and I went on to research how to structure projects for this, but didn't find anything useful. What I did find is $PropertyType utility class, that led me to the following approach
// @flow
import React, {Component}
import OtherComponent from "./OtherComponent"
export type MyComponentProps = {
something: string
}
export type MyComponentState = {
something2: boolean
}
export type MyComponentActions = {
check: (
something2: $PropertyType<MyComponentState, 'something2'>,
something: $PropertyType<MyComponentProps, 'something'>
) => string
}
class MyComponent extends Component<MyComponentProps, MyComponentState> {
state = { something: /* comes from somewhere else i.e store */ false }
check: $PropertyType<MyComponentActions, 'check'> = (something2, something) => something2 ? "Default" : something
render() {
return <OtherComponent foo={this.check} />
}
}
This is a somewhat of useless example, but it shows the pattern I chose, this way OtherComponent
can import these types i.e. for check
function and use $PropertyType
in it when it is specifying its foo
prop type.
It works, but is extremely verbose, hence I wanted to ask community for alternative suggestions.
My main goal is to be able and re-use these types without the need to re-type them a lot in a clean manner.
There is no "best project architecture" that will fit with any project and coding style. But you should always structure your project. React doesn't follow any particular project structure, and the positive thing about this is that it allows us to make up a structure to suit our needs.
Solution: We can use a custom hook that will allow us to reuse this toggle logic in both components, and in any new component added in the future.
The simplest folder structure for this case seems to be the “group files by their types” option mentioned in the React docs. This makes our lives easy: Components go in the components folder, hooks in the hooks folder, and contexts in the contexts folder.
I don't think there is a general answer to this problem and I cannot give you a definite answer here. I have been working with flow now extensively for 1,5 years and also together with React for a year now. Here are some tips for working with types.
1. Use type inference
Flow is really powerful when it comes to inferring types. Together with the following tips you can avoid making a lot of annotations. Flow will just figure out that things work. You can also make use of the typeof
annotation to get the type of a value.
2. Model your domain with types not the interfaces of the components
This was mentioned in the comments already. Use types to model your domain. E.g. if you work with a component that displays a user, model the user object, not the interface of the component. You can then import the user type in the components that use it.
type User = { id: string, name: string };
type ProfilePropType = { user: User };
class Profile extends Component<ProfilePropType> {
// ...
}
3. Use state management
Redux for example could help you with the types here. This will give you a structure for your domain types and also reduces how many props are passed around. Another blessing is GraphQL and Apollo Client / Relay.
4. Generate types programmatically
We are generating types from our Postgres schema via postloader in the backend and types for our GraphQL queries in the frontend. Currently we are working on generating types for react-semantic-ui from their documentation. After that there are not many types left to write ourselves. There are probably some tools around for your use case.
One last thing:
Types are verbose. Sometimes it is good to be explicit. The idea is that types reduce the time you spend searching for bugs by forcing you to be explicit about things. Often it is okay to redefine things. This will also lead to way better errors than using $PropertyType
because Flow will give you two types that are incompatible instead of cryptic messages.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With