如何使用 Flow 描述 Immutable.js 地图形状

How to describe Immutable.js Map shape with Flow

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

您可以通过以下方式描述物体的形状:

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

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

TL;DR;

不,但是使用 Records 可以让 Flow 对形状而不是类型进行类型检查。

长篇

正确的答案是:不,因为地图没有形状 (至少在 Flow 中是这样和不可变)。但是 Immutable 确实有一个带有形状的 "Maps" 类型。那将是 记录 。但是由于下面描述的原因(因为它不是严格相关的)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. But we still can't define the types of the actual values. Flow does define an undocumented $PropertyType<T, K> type. Which takes an object T and a string literal K. To make $PropertyType work in our case it would need to work for $Keys<T> which is a string union type. A few weeks ago an issue was opened to make this happen. It can be found here.

地图与对象的区别

在流程上,它们是截然不同的。这是一张地图:

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

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

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

当创建或更改对象时,newObj,类型为 MyObject Flow,将检查 newObj.a 是一个字符串并且 newObj.x 是一个布尔值。

为什么现在的定义这么宽松

A Record 通过直接键访问公开每个 key/value 对。

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.