Как описать карту Immutable.js с потоком

Я хотел бы описать форму карты, используя определения типа Неизменяемого потока.

Вы можете описать форму объекта:

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

Есть ли что-то подобное для неизменяемых карт?

Ответ 1

TL; DR;

Нет, но используя записи, вы можете получить Flow для typecheck формы, но не типы.

полной формы

Правильный ответ: нет, поскольку карты не имеют форм (по крайней мере, в потоке и неизменяемом). Но Immutable имеет тип "Карты" с фигурами. Это будет Записи. Но по причинам, описанным ниже (поскольку это не очень важно) поток libdef для Immutable.Record очень свободен и фактически не проверяет формы.

Лучшая запись libdef

Если мы игнорируем (возможно ненужную) функцию прямого доступа к свойствам записи, мы можем создать лучший 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>;
}

С помощью этого объявления мы можем определить форму записи. Здесь он находится в действии. Но мы все еще не можем определить типы фактических значений. Flow определяет недокументированный тип $PropertyType<T, K>. Который берет объект T и строковый литерал K. Чтобы сделать $PropertyType работать в нашем случае, ему нужно будет работать для $Keys<T>, который является типом объединения строк. Несколько недель назад была открыта проблема, чтобы это произошло. Здесь можно найти.

Разница между Map и Object

В потоке они довольно разные. Это карта:

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

Фактические ключи неизвестны. Единственное, что Flow знает, состоит в том, что все ключи должны быть строками, а все значения должны быть числами. С другой стороны, тип объекта выглядит примерно так:

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

При создании или изменении объекта newObj типа MyObject Flow проверяет, что newObj.a является строкой, а newObj.x является логическим.

Почему текущее определение так свободно

A Запись предоставляет каждую пару ключ/значение через прямой доступ к ключам.

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

Это потребует определения типа r как пересечения Record<R> и r (не совсем, но достаточно близко). Итак:

(r: R & Record<R>)

Это не работает, потому что Flow не поддерживает поддержку типов пересечений с объектами. Вот как это выглядит в действии.