我试图定义一个对象必须没有某个键。
以下是我的案例:
alert({
items: [{ label:'Apple' }, { label:'Orange' }]
})
alert({
items: [{ foo:'Apple' }, { foo:'Orange' }]
labelKey: 'foo'
})
如果items是不包含“label”键的对象数组,则选项中需要labelKey
我试过了:
type Options = {|
items: Array<{ label:string }>
|} | {|
items: Array<$Diff<{}, { label:string }>>,
labelKey: string // must be key in items
|}
function alert(options: Options) {
}
奖金问题: 还可以定义labelKey是来自项目中传递的对象的任何键吗?
答案 0 :(得分:2)
{ myProp?: empty }
我假设您在将某些内容传递到alert
函数时想要使用objects as maps。创建没有标签的地图的技巧是给出一个属性,如果分配给某个属性,将无法进行类型检查。
我们可以利用empty
type,这是一种与任何东西都不匹配的类型,以获得理想的效果。将empty
类型与对象映射结合使用有点棘手,因为通过定义属性,我们告诉流我们想要该类型在对象中。所以这没有成功:
(Try)
type MapWithLabel = {
[string]: string,
label: string,
}
type MapWithoutLabel = {[string]: mixed, label: empty}
type Options = {|
items: Array<MapWithLabel>
|} | {|
labelKey: string,
items: Array<MapWithoutLabel>,
|}
declare function alert(options: Options): void;
alert({
items: [{ foo:'Apple' }], // Error, expected a "label" property with empty type
labelKey: 'foo'
})
接下来,我们可以将属性定义为optional,这意味着如果属性存在,则仅对empty
进行类型检查。有了这个,我们可以给对象一个&#34;标签&#34;属性:
因此代码可能没有该属性的值(我们想要的),或者它可以传递一些空的东西(这是不可能的)。
(Try)
type MapWithLabel = {
[string]: string,
label: string,
}
type MapWithoutLabel = {[string]: mixed, label?: empty}
type Options = {|
items: Array<MapWithLabel>
|} | {|
labelKey: string,
items: Array<MapWithoutLabel>,
|}
declare function alert(options: Options): void;
alert({
items: [{ label:'Apple' }],
})
alert({
items: [{ label:'Apple' }], // Error - Should not have label
labelKey: 'ohno',
})
alert({
items: [{ foo:'Apple' }],
labelKey: 'foo'
})
alert({
items: [{ foo:'Apple' }], // Error - Needs a labelKey
})
为了获得预期的效果,我们需要利用两个工具:可选属性和empty
类型。有了它,我们可以指定一个对象,如果empty
属性存在,将无法进行类型检查。
关于奖金问题:我不确定Flow能否理解,因为我不知道如何在对象上设置变量属性。我不希望这个功能,因为它可能使复杂/不可能键入检查。
编辑:经过一番研究后,可以使用indexer properties断言对象在类型级别有一个键:
(Try)
type ObjWithKey<T: string = 'label'> = {
// An indexer property with only one valid value: T with "label"
// as default, but we can't ensure that the property exists anymore
// and multiple indexers are not supported.
[T]: string,
aNumber: 3,
aFunction: () => void,
}
declare var usesLabel: ObjWithKey<>
(usesLabel.label: string);
(usesLabel.aNumber: number);
(usesLabel.missing: number); //Error - Doesn't exist on object
(usesLabel.aFunction: () => void);
(usesLabel.aFunction: string); //Error - Wrong type
但是,您不能这样做和将该对象用作常规映射,因为不支持多个索引器属性(Try)。作为参考,其他人试图做其他类似的事情but couldn't get it to work。
如果这对您来说是一个主要问题,请查看您是否可以采用不同的方式构建数据结构,以便更轻松地使用Flow进行静态分析。