Open MOZGIII opened 7 years ago
FYI: I've just changed the way code is organized in my project as a workaround. But this particular sample is interesting just as a usecase example.
@MOZGIII from what I can tell the design here may flawed in a few ways. I couldn't tell completely what you were trying to accomplish, but it did seem needlessly complex (making it hard to type as well).
If you want a normalized object and you want to transform keys etc then flow isn't going to be able to type it very well. It can't take a string literal
and generate a new string literal from it (hello
=> hello_world
), so you would need to change to using string
typing only which probably is not ideal.
An alternative would be to instead use Flow to describe a transformation and use a layered object.
If you were to do that then you would be able to type this much more naturally and create code which is far easier to read.
Note: I had a pretty hard time understanding specifically what you were trying to accomplish here and didn't feel like taking the time to really break it down. This seems to do something along the lines of what you were tyring to do.
I didn't know what MatchType
was supposed to be so I changed that to any
and *
was changed to mixed
The below should also provide 100% coverage which would have been difficult with the first example.
// @flow
import * as utils from './utils';
import toCamelCase from './toCamelCase';
const map = {
root: '/',
login: '/login',
logout: '/logout',
workspace: '/workspaces/:workspace_id',
import: '/workspaces/:workspace_id/import',
assets: '/workspaces/:workspace_id/assets',
asset: '/workspaces/:workspace_id/assets/:id',
preferences: '/workspaces/:workspace_id/user/preferences',
files: '/workspaces/:workspace_id/files',
};
type MatchType = any;
export type RouteNames = $Keys<typeof map>;
type RouteMap<T> = {|
+pattern: $ElementType<typeof map, T>,
+path: (params: mixed) => string,
+matchPath: (path: string) => MatchType,
+matchSub: (path: string) => MatchType,
|};
type TransformRoutesMap = <T>(T) => RouteMap<T>;
export type RoutesMapped = $ObjMapi<typeof map, TransformRoutesMap>;
const helpers: $Exact<RoutesMapped> = Object.keys(map).reduce(
(p: $Shape<RoutesMapped>, key): $Shape<RoutesMapped> => ({
...p,
[key]: {
pattern: map[key],
path: (params: mixed): string => utils.generatePath(key, params),
matchPath: (path: string): MatchType => utils.matchPath(key, path),
matchSub: (path: string): MatchType => utils.matchSubPath(key, path),
},
}),
({}: $Shape<RoutesMapped>),
);
const workspace = helpers.workspace;
// $Works
(workspace.pattern: '/workspaces/:workspace_id');
// $Works
(workspace: RouteMap<'workspace'>);
// $ExpectError
(workspace: RouteMap<'assets'>);
export default helpers;
Essentially it ends up taking your map
object and creating a type where each key becomes an object that matches RouteMap
where its value (pattern) is added to a key (pattern) and the rest follows.
Example:
const mapped = {
workspace: {
pattern: '/workspaces/:workspace_id',
path: (params: mixed): string => utils.generatePath('workspace', params),
matchPath: (path: string): MatchType => utils.matchPath('workspace', path),
matchSub: (path: string): MatchType =>
utils.matchSubPath('workspace', path),
},
// ...rest here
};
Finally here is a screenshot to help see what the $ObjMapi
does here:
Hello!
Here's my usecase for flow, and I need help with it. I have a code like below, and I want to add poper types for functions that are exptored from this module (and for helpers object).
The code is:
Expected types would look like this (for each entry in
map
):How can I achieve this?