我有两种相似但截然不同的结构:
type A = { foo: string, bar: string, specialA: string };
type B = { foo: string, bar: string, specialB: string };
我正在使用reselect
here中的类型使用flow-typed
创建选择器。我所做的唯一修改是导出OutputSelector类型。
我有三个文件,其用途如下:
generic.js
:使用以下模式导出通用选择器:
export const someSelector = selector => createSelector(selector, ...)
a.js
:像这样导出特定于type A
的选择器:
import { someSelector } from './generic.js';
const aSelector = state => state.a;
export selector = someSelector(aSelector);
b.js
:与a.js
相同,但对于type B
因此,我的想法是将特定选择器传递给通用选择器,该选择器将选择适当的类型。我在制作它时遇到麻烦,以便在某处使用特定选择器时保留类型信息。因此,某些文件只关心type A
,因此它从a.js
导入选择器,但是Flow抱怨返回的对象可以具有A
或B
的道具。由于很难准确地找到所有错误的出处,因此我将选择器复制粘贴到a.js
和b.js
中,并确保在不涉及泛型的情况下它们可以工作。然后,我将一个选择器移到generic.js
中,以尝试缩小问题的范围。我有这个:
type Base = { foo: string, bar: string };
type SpecificSelector<T> = OutputSelector<State, mixed, T>;
export const selector = <T: Base, A: $ReadOnlyArray<T>, R: { [string]: $ReadOnlyArray<T> }>(specificSelector: SpecificSelector<A>) =>
createSelector(
specificSelector,
(arr: A): R => groupBy(arr, (o: T): mixed => finding.foo),
);
lodash
的{{1}}的定义:
groupBy
我得到的错误:
groupBy<V, T>(
array: $ReadOnlyArray<T>,
iteratee?: ?ValueOnlyIteratee<T>,
): { [key: V]: $ReadOnlyArray<T> };
我不明白为什么它们不兼容。如果删除通用参数Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ apps/acheron/src/selectors/util/generic.js:70:23
Cannot return groupBy(...) because object type [1] is incompatible with R [2].
apps/acheron/src/selectors/util/generic.js
67│ export const selector = <T: Base, A: $ReadOnlyArray<T>, R: { [string]: $ReadOnlyArray<T> }>(specificSelector: SpecificSelector<A>) => createSelector(
68│ specificSelector,
69│
[2] 70│ (arr: A): R => groupBy(arr, (o: T): mixed => o.foo),
71│ );
72│
flow-typed/npm/lodash_v4.x.x.js
[1] 708│ ): { [key: V]: $ReadOnlyArray<T> };
并仅返回R
返回的值,那么我会遇到另一个问题:
groupBy
新错误:
export const selector1 = <T: Base, A: $ReadOnlyArray<T>>(specificSelector: SpecificSelector<A>) => createSelector(
specificSelector,
(arr: A): {[string]: $ReadOnlyArray<T>} => groupBy(arr, (o: T): mixed => o.foo),
);
export const selector2 = <T: Base, A: $ReadOnlyArray<T>>(specificSelector: SpecificSelector<A>) => createSelector(
[selector1(specificSelector),
(state: State, props: mixed): ?string => props && props.match && props.match.params && typeof props.match.params.appId === 'string' ? props.match.params.appId : null],
(arr: {[string]: $ReadOnlyArray<T>}, appId: ?string): ?$ReadOnlyArray<T> =>
arr && appId && arr[appId]
? arr[appId]
: null,
);
我理解这是因为lodash返回的对象不再是通用参数,类型信息正在丢失,并且Flow无法确保两个对象中都包含相同的键吗?