如何用Flow描述Immutable.js Map形状

时间:2016-05-04 16:31:52

标签: immutable.js

我想使用Immutable的流类型定义来描述地图的形状。

您可以通过以下方式描述对象的形状:

const stateShape: {
  id: number,
  isActive: boolean
} = {
  id: 123,
  isActive: true
};

Immutable的地图有类似内容吗?

1 个答案:

答案 0 :(得分:29)

TL; DR;

不,但是使用记录你可以获得Flow来检查形状而不是类型。

长片

正确的答案是:否,因为地图没有形状 (至少在Flow和Immutable中)。但 Immutable 确实有一个带有形状的“地图”类型。这将是记录。但由于下面描述的原因(因为它并不严格相关),Immutable.Record的流量libdef非常松散,实际上并不检查形状。

更好的Record libdef

如果我们忽略直接访问Record属性的(可以说是不必要的)功能,我们可以创建一个更好的libdef。看起来像这样:

declare class Record<T: Object> {
  static <T: Object>(spec: T, name?: string): Record<T>;
  get: <A>(key: $Keys<T>) => A;
  set<A>(key: $Keys<T>, value: A): Record<T>;
  remove(key: $Keys<T>): Record<T>;
}

通过此声明,我们可以定义记录的形状Here it is in action。但是我们仍然无法定义实际值的类型。 Flow确实定义了一个未记录的$PropertyType<T, K>类型。其中包含对象T和字符串文字K。为了使$PropertyType能够在我们的情况下工作,它需要适用于$Keys<T>这是一个字符串联合类型。几个星期前,为了实现这一目标,已经开启了一个问题。 It can be found here

地图和对象之间的差异

在流程中他们是完全不同的。这是一张地图:

type MyMaps = { [key: string]: number }

实际的密钥未知。 Flow知道的唯一事情是所有键必须是字符串,所有值必须是数字。另一方面,对象类型看起来像:

type MyObject = { a: string, x: boolean }

创建或更改newObj类型的MyObject对象时,会检查newObj.a是否为字符串,newObj.x是否为布尔值。

为什么当前的定义如此松散

记录通过直接密钥访问公开每个键/值对。

type R = { a: string }
const r = Record({ a: 'Supa' })
r.a === r.get('a')

这需要r的类型定义为Record<R>R的交叉(不完全相同,但它足够接近)。所以:

(r: R & Record<R>)

这不起作用,因为Flow缺少对具有对象的交叉类型的支持。 Here's how that looks in action