在Flow中注释对包含可选参数的联合类型进行操作的函数

dum*_*ter 2 javascript flowtype

我为糟糕的头衔道歉,我不知道如何更好地描述这个:)

我在基于具有自动递增ID的IndexedDB数据库的应用程序中使用Flow.所以基本上,我创建了一些对象(没有id属性),将它们写入数据库(此时它们被idIndexedDB 赋予属性),然后将它们读回(从DB读取的任何对象都保证有数字)id属性).

我有一些操作这些对象的函数.有时它们只对具有ID的对象进行操作,有时它们只对没有ID的对象进行操作,有时它们同时对两者进行操作.这是最棘手的后一种情况.这是一次尝试,在写入数据库之前和之后使用两种不同类型的对象(因此,分别没有和使用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);
Run Code Online (Sandbox Code Playgroud)

(演示链接)

这会在最后一行产生错误,因为它不知道x类型是什么,AfterDb我不确定如何恰当地传达这些信息.

另一个想法是使用有界多态性,除了我不相信这可以创建类似我a上面的函数,因为它无法处理id有时未定义的事实.就像我想做这样的事情:

function a<T: {id?: number}>(obj: T): T {
  if (typeof obj.id === 'number') {
    console.log(obj.id * 2);
  }
  return obj;
}
Run Code Online (Sandbox Code Playgroud)

(演示链接)

但这不起作用.如果我分配了一个虚拟值,id所以它总是数字(比如-1而不是undefined)那么这可以工作,但是我必须非常小心地记住id在第一次写入DB之前删除它所以真实id可以自动生成,这将是非常难看的.

在那之后,我几乎是出于好主意.我要做的一件事就是只使用一种类型,例如:

type Obj = {id?: number, prop: string};
Run Code Online (Sandbox Code Playgroud)

然后显式检查id属性是否存在于使用该id属性的每个函数中.但这很烦人,因为我有一堆只用IndexedDB的输出调用的函数,所以我已经知道id保证在那里.我只是不知道怎么告诉Flow.

有任何想法吗?

gca*_*nti 5

function a<T: BeforeDb | AfterDb>(obj: T): T {
  if (typeof obj.id === 'number') {
    console.log(obj.id * 2);
  }
  return obj;
}
Run Code Online (Sandbox Code Playgroud)