Flow 中对包含可选参数的联合类型进行操作的注释函数
Annotating functions in Flow that operate on union types containing optional parameters
我为糟糕的标题道歉,我不知道如何更好地描述它:)
我在基于具有 auto-incrementing ID 的 IndexedDB 数据库的应用程序中使用 Flow。所以基本上,我创建了一些 objects(没有 id
属性),将它们写入数据库(此时它们被赋予 id
属性通过 IndexedDB),然后将它们读回(从数据库读取的任何 object 保证有一个数字 id
属性)。
我有一些函数可以在这些 object 上运行。有时它们只对有 ID 的 object 进行操作,有时它们只对没有 ID 的 object 进行操作,有时它们对两者都进行操作。最棘手的是后一种情况。这是一种尝试,在写入数据库之前和之后对 object 使用两种不同的类型(因此,分别没有和使用 id
属性):
/* @flow */
type BeforeDb = {prop: string};
type AfterDb = BeforeDb & {id: number};
var beforeDb: BeforeDb = {prop: 'hi'};
var afterDb: AfterDb = {id: 1, prop: 'hi'};
function a(obj: BeforeDb | AfterDb): BeforeDb | AfterDb {
if (typeof obj.id === 'number') {
console.log(obj.id * 2);
}
return obj;
}
function b(obj: AfterDb) {}
var x = a(afterDb);
b(x);
这会在最后一行产生错误,因为它不知道 x
是 AfterDb
类型,而且我不确定如何适当地传达该信息。
另一个想法是使用 bounded polymorphisms,但我不相信这可以创建类似我上面的 a
函数的东西,因为它无法处理 id
有时是未定义的。就像我想做这样的事情:
function a<T: {id?: number}>(obj: T): T {
if (typeof obj.id === 'number') {
console.log(obj.id * 2);
}
return obj;
}
但这不起作用。如果我为 id
分配了一个虚拟值,所以它始终是数字(比如 -1 而不是未定义)那么这会起作用,但是我必须非常小心记住删除 id
在第一次写入数据库之前,所以真正的 id
可能是 auto-generated,这会很丑陋。
在那之后,我几乎没有什么好主意了。我要做的一件事就是只使用一种类型,比如:
type Obj = {id?: number, prop: string};
然后明确检查 id
属性 是否存在于每个使用 id
属性 的函数中。但这很烦人,因为我有一堆函数只用 IndexedDB 的输出调用,所以我已经知道 id
肯定在那里。我只是不知道如何告诉 Flow。
有什么想法吗?
function a<T: BeforeDb | AfterDb>(obj: T): T {
if (typeof obj.id === 'number') {
console.log(obj.id * 2);
}
return obj;
}
我为糟糕的标题道歉,我不知道如何更好地描述它:)
我在基于具有 auto-incrementing ID 的 IndexedDB 数据库的应用程序中使用 Flow。所以基本上,我创建了一些 objects(没有 id
属性),将它们写入数据库(此时它们被赋予 id
属性通过 IndexedDB),然后将它们读回(从数据库读取的任何 object 保证有一个数字 id
属性)。
我有一些函数可以在这些 object 上运行。有时它们只对有 ID 的 object 进行操作,有时它们只对没有 ID 的 object 进行操作,有时它们对两者都进行操作。最棘手的是后一种情况。这是一种尝试,在写入数据库之前和之后对 object 使用两种不同的类型(因此,分别没有和使用 id
属性):
/* @flow */
type BeforeDb = {prop: string};
type AfterDb = BeforeDb & {id: number};
var beforeDb: BeforeDb = {prop: 'hi'};
var afterDb: AfterDb = {id: 1, prop: 'hi'};
function a(obj: BeforeDb | AfterDb): BeforeDb | AfterDb {
if (typeof obj.id === 'number') {
console.log(obj.id * 2);
}
return obj;
}
function b(obj: AfterDb) {}
var x = a(afterDb);
b(x);
这会在最后一行产生错误,因为它不知道 x
是 AfterDb
类型,而且我不确定如何适当地传达该信息。
另一个想法是使用 bounded polymorphisms,但我不相信这可以创建类似我上面的 a
函数的东西,因为它无法处理 id
有时是未定义的。就像我想做这样的事情:
function a<T: {id?: number}>(obj: T): T {
if (typeof obj.id === 'number') {
console.log(obj.id * 2);
}
return obj;
}
但这不起作用。如果我为 id
分配了一个虚拟值,所以它始终是数字(比如 -1 而不是未定义)那么这会起作用,但是我必须非常小心记住删除 id
在第一次写入数据库之前,所以真正的 id
可能是 auto-generated,这会很丑陋。
在那之后,我几乎没有什么好主意了。我要做的一件事就是只使用一种类型,比如:
type Obj = {id?: number, prop: string};
然后明确检查 id
属性 是否存在于每个使用 id
属性 的函数中。但这很烦人,因为我有一堆函数只用 IndexedDB 的输出调用,所以我已经知道 id
肯定在那里。我只是不知道如何告诉 Flow。
有什么想法吗?
function a<T: BeforeDb | AfterDb>(obj: T): T {
if (typeof obj.id === 'number') {
console.log(obj.id * 2);
}
return obj;
}