Подтвердить что ты не робот

Можно ли обернуть тип потока в неизменяемом контейнере?

Например, учитывая следующую запись:

type UserRecord = {
  id: string;
  name: ?string;
  age: number;
}

Есть ли способ сделать эквивалент следующего:

/* @flow */

import { List, Map } from 'immutable'

const users: List<Map<UserRecord>> = List();    
let user: Map<UserRecord>;

user = Map({ id: '666', age: 30 });
users.push(user);

В противном случае я просто использую что-то вроде Map<string, any>, которое, как мне кажется, уходит от использования Immutable.js с системой типа Flow.

4b9b3361

Ответ 1

В целом это невозможно, так как записи и карты имеют очень разную семантику. Тип карты параметризуется с помощью типов ключа и значения, поэтому при вызове .get вы получите одинаковый тип для всех ключей.

Однако есть способ:

declare class Map<T, K1=null, V1=null, K2=null, V2=null> {

  constructor(val: T): void;

  get(key: K1 & $Keys<T>): V1;
  get(key: K2 & $Keys<T>): V2;
  // etc
}

const m: Map<{ foo: string, bar: number }, 'foo', string, 'bar', number> = new Map({
  'foo': 'foo',
  bar: 42
});


m.get('foo') // string
m.get('bar') // number
m.get('baz') // error

Вероятно, хорошая идея создать такое объявление с помощью своего рода script для поддержки желаемого количества пар ключ-значение.

Такое объявление является немного подробным, но безопасным, если вы не испортите параметры типа. Несколько комментариев:

  • мы используем функцию недавнего потока, которая позволяет объявить параметр типа по умолчанию, чтобы мы могли использовать одно объявление для любого количества пар ключ-значение;

  • K1 & $Keys<T> гарантирует, что мы можем использовать только фактические ключи типа T для извлечения значений; это помогает в некоторой степени, к сожалению, я не нашел способа проверить согласованность типов значений, поэтому вы должны быть осторожны с ними.