We're using Flow in our project and I'm chasing my tail on this one. Am using React Context to store a user's favourite assets, this will be used in multiple places. I can't get Flow happy with React Context whose value
is an object as follows:
// this is the problem line!! currently having to $FlowIgnore it
export const FavoriteAssetsContext = React.createContext(undefined);
// this is all fine
export function FavoriteAssetsProvider({
children,
}: FavoriteAssetsProviderProps): React.Node {
const [favoriteAssets, setFavoriteAssets] = useState([]);
const [favoriteAssetIds, setFavoriteAssetIds] = useState([]);
const _isFavorite = (asset: Asset): boolean => { // private func };
const addFavorite = useCallback((asset: Asset): void => {
// exported function - performs setState, no return value
});
const removeFavorite = useCallback((asset: Asset): void => {
// exported function - performs setState, no return value
});
return (
<FavoriteAssetsContext.Provider
value={{ favoriteAssets, favoriteAssetIds, addFavorite, removeFavorite }}
>
{children}
</FavoriteAssetsContext.Provider>
);
}
So the consumers of the context can access four properties on the value
object. Flow is complaining about the lack of typing of the FavoriteAssetsContext
which we export.
Per the Flow docs I've tried this:
type FavoriteAssetsContextType = {
favoriteAssets: Array<Asset>,
favoriteAssetIds: Array<string>,
addFavorite: (asset: Asset) => void,
removeFavorite: (asset: Asset) => void,
};
export const FavoriteAssetsContext = React.createContext<FavoriteAssetsContextType>({});
but I get the following error:
Cannot build a typed interface for this module. You should annotate the exports of this module with types. Cannot determine the type of this call expression. Please provide an annotation, e.g., by adding a type cast around this expression. [signature-verification-failure]
I have tried several permutations and combinations of type casting per Flow docs, which all look horribly wrong. It's complaining about the right hand side so I tried the following syntax:
// without generic - shouldn't be needed right?
export const FavoriteAssetsContext = (React.createContext({}) : FavoriteAssetsContextType);
// and with generic - ???
export const FavoriteAssetsContext = (React.createContext<FavoriteAssetsContextType>({}) : FavoriteAssetsContextType);
but both times I get
Cannot cast React.createContext<...>(...) to FavoriteAssetsContextType because property removeFavorite is missing in React.Context [1] but exists in FavoriteAssetsContextType [2]. [prop-missing]
The docs have simple examples whereby the value
is a simple string and an extensive search hasn't come up with anything examples where value
is an object. Any help much appreciated!
type FavoriteAssetsContextType = {
favoriteAssets: Array<Asset>,
favoriteAssetIds: Array<string>,
addFavorite: (asset: Asset) => void,
removeFavorite: (asset: Asset) => void,
};
export const FavoriteAssetsContext = React.createContext<FavoriteAssetsContextType>({});
This one solution is in the right direction however currently content is initialised with the empty object ({}
), but in the type that is provided in the FavoriteAssetsContextType
there are expected values for all the keys in it.
So the solution can be to update FavoriteAssetsContextType
making all keys optional:
type FavoriteAssetsContextType = {
favoriteAssets?: Array<Asset>,
favoriteAssetIds?: Array<string>,
addFavorite?: (asset: Asset) => void,
removeFavorite?: (asset: Asset) => void,
};
Or to make an empty object acceptable value:
type FavoriteAssetsContextType = {
favoriteAssets: Array<Asset>,
favoriteAssetIds: Array<string>,
addFavorite: (asset: Asset) => void,
removeFavorite: (asset: Asset) => void,
} | {};