我想要定义一个实体映射,这样键必须始终是某个指定类型的其他对象的ID。所需的用法如下:
export type Id<T> = {
id: string
};
export type Foo = Id<Foo> & {
val: number
};
// type Foo is now {id: Id<Foo>, val: number}
export type Bar = Id<Bar> & {
val: number
};
// type Bar is now {id: Id<Bar>, val: number}
// FooMap should only be able to store objects of type foo, referenced by
// IDs of type Id<Foo>
export type FooMap = {
[key: Id<Foo>]: Foo
};
const foo1: Foo = { id: "foo1", val: 1 };
const foo2: Foo = { id: "foo2", val: 2 };
const bar1: Bar = { id: "bar1", val: 3 };
// This would pass type checking:
const fooMap: FooMap = {
[foo1.id]: foo1,
[foo2.id]: foo2
};
// But this would fail type checking:
const badMap: FooMap = {
[bar1.id]: foo1
};我的用例是,我希望有一个规范化的对象结构,通过ID管理关系。但是,由于ID都是相同的底层类型(例如,string或number),所以可能会意外地编写类似于上面的badMap示例的代码。我希望FlowType能够帮助防止这种情况的发生,因为我要求在以编程方式构造映射时只能引用正确的ID类型。
发布于 2017-03-07 21:57:15
从概念上讲,我认为您需要一个带有标记的联合类型来表示您正在使用的各种is -下面是F#:单一案件歧视工会中的一个例子。
如果我正确地理解了您,您希望创建像Map<FooId, Foo>这样的映射,其中fooMap[someFooId]只能包含一个Foo对象。但是,由于FooId可能是与BarId相同的类型,所以您可能在映射中有someBarId: Foo。你想要流向可能发生这种情况的打字机箱。
不幸的是,我不认为现在有一个简单的方法来做到这一点,因为它缺乏单一的案例标记的工会。在F#中,您可以这样做:
type FooId = FooId of string
type BarId = BarId of string
type Id<'T> = Id of 'T // you'd pass in FooId as the type
type Foo = {
id: Id<FooId>;
value: string;
}
type Bar = {
id: Id<BarId>;
value: string;
}
let foo: Foo = { id = Id (FooId "12345"); value = "fooVal" }
let bar: Bar = { id = Id (BarId "12345"); value = "barVal" }
let fooMap =
Map.empty<Id<FooId>, Foo>
|> Map.add (Id (BarId "12345")) foo在JavaScript里我能得到的最接近的东西就是这样的东西。这方面的问题是类型错误发生在FooId/BarId的定义上。我们得到:
string literal `FooId`. Expected string literal `BarId`, got `FooId` instead
string literal `BarId`. Expected string literal `FooId`, got `BarId` insteadThe JavaScript:
type FooId = "FooId";
type BarId = "BarId";
type Id<T> = {
id: string;
type: T
};
type Foo = {
id: Id<FooId>,
val: any
};
type Bar = {
id: Id<BarId>, // get type error here
val: any
};
type FooMap = {
[key: Id<FooId>]: Foo // get type error here
};
const fooIdBuilder = (id): Id<FooId> => ({ id, type: "FooId" });
const barIdBuilder = (id): Id<BarId> => ({ id, type: "BarId" });
const foo1: Foo = {
id: fooIdBuilder("12345"),
val: "fooval"
};
const foo2: Foo = {
id: fooIdBuilder("23456"),
val: "fooval"
};
const bar1: Bar = {
id: barIdBuilder("23456"),
val: "barval"
};
const fooMap: FooMap = {};
fooMap[foo1.id] = foo1;
fooMap[bar1.id] = foo2;您可以复制并粘贴到试流中。
https://stackoverflow.com/questions/42404668
复制相似问题