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

Wil*_*iam 40 immutable.js

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

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

const stateShape: {
  id: number,
  isActive: boolean
} = {
  id: 123,
  isActive: true
};
Run Code Online (Sandbox Code Playgroud)

Immutable的地图有类似的东西吗?

Kri*_*tig 30

TL; DR;

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

长表

正确的答案是:不,因为地图不具有形状 (至少在流量和不可变的).但是Immutable确实有一个带有形状的"地图"类型.这将是记录.但由于下面描述的原因(因为它并不严格相关),流程libdef Immutable.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>;
}
Run Code Online (Sandbox Code Playgroud)

通过此声明,我们可以定义Record的形状.这是在行动.但是我们仍然无法定义实际值的类型.Flow确实定义了一个未记录的$PropertyType<T, K>类型.它接受一个对象T和一个字符串文字K.为了$PropertyType在我们的案例中工作,它需要工作为$Keys<T>字符串联合类型.几个星期前,为了实现这一目标,已经开启了一个问题.它可以在这里找到.

Map和Object之间的区别

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

type MyMaps = { [key: string]: number }
Run Code Online (Sandbox Code Playgroud)

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

type MyObject = { a: string, x: boolean }
Run Code Online (Sandbox Code Playgroud)

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

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

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

type R = { a: string }
const r = Record({ a: 'Supa' })
r.a === r.get('a')
Run Code Online (Sandbox Code Playgroud)

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

(r: R & Record<R>)
Run Code Online (Sandbox Code Playgroud)

这不起作用,因为Flow缺少对具有对象的交叉类型的支持.这是看起来如何行动.

  • 这个问题仍然存在,或者自从这个答案以来已经进一步发展了? (8认同)
  • 从immutable检查RecordOf <>和RecordFactory <>新类型 (3认同)