实施类型化不可变数据结构的更简单方法?

Easier way to enforce typed immutable data structures?

使用原始 JS 对象和流程实施数据结构很容易:

type ExampleObjType = {
  key1: number,
  key2: string
};

const obj: ExampleObjType = {
  key1: 123,
  key2: '123'
};

似乎这需要大量不必要的样板文件才能在 Immutable 中强制执行类似的结构:

type TestSpec = {
  key1: number,
  key2: string,
};

const TestRecord = Record({
  key1: 0,
  key2: '',
});

const record: TestSpec & Record<TestSpec> = new TestRecord({
  key1: 123,
  key2: '123',
});

此外,上述结构有一些主要缺点:

理想情况下,我可以使用 Immutable.Map,像这样:

type TestSpec = Map<{key1: number, key2: number}>;

const testMap: TestSpec = Map({
  key1: 123,
  key2: '123',
});

但是,当前的实现只允许键入键和值类型。我可以使用诸如 type Key = 'key1' | 'key2' 之类的东西来限制键类型,但这仍然不能让我明确键入每个键的值。

有没有办法用 Immutable 实现我正在寻找的东西?这似乎是真正类型安全的一个非常基本的要求,特别是当用于 Redux 操作有效负载时。

immutable.Record()很难打字。事实上,it's currently typed到returnany。一方面,这很不方便,因为您需要从头开始描述 TestRecord 的类型。另一方面,它可以让您随心所欲地输入!

这是一种选择:

interface TestSpec {
  constructor(defaults: $Shape<TestSpec>): void,
  key1: number,
  key2: string,
};

const TestRecord: Class<TestSpec> = Record({
  key1: 0,
  key2: '',
});

Class<TestSpec> 类型是 class 实例的类型 TestSpec。您不必在 TestSpec 中定义构造函数,但通过这样做,Flow 将确保 obj 在看到 new TestRecord(obj).

时有正确的时间

(注意:$Shape<TestSpec>是对象的类型,可能有也可能没有。所以在这种情况下它基本上意味着{key1?: number, key2?: string}

new TestRecord({key1: 123,  key2: '123'}); // OK
new TestRecord({key1: 123}); // OK
new TestRecord({key2: '123'}); // OK

new TestRecord({key2: 123}); // Error number -> string
new TestRecord({key1: '123'}); // Error string -> number
new TestRecord({key1: 123,  key2: '123', key3: 'blah'}); // Error unknown property key3

Flow 将检查实例属性的类型是否正确

const record = new TestRecord({key1: 123,  key2: '123'});
(record.key1: string); // Error number -> string
(record.key2: number); // Error string -> number

Try this code on flowtype.org/try