实施类型化不可变数据结构的更简单方法?
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
使用原始 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