向对象添加属性的函数

时间:2017-01-09 18:44:02

标签: javascript flowtype

将Flow注释添加到像这样的函数中的正确/首选方法是什么?

function addBar(foo) {
  foo.bar = 10
  return foo
}

我们说我有以下类型:

type Foo = { foo: string }
type FooBar = { foo: string, bar: number }

我希望该功能可以接收Foo并返回FooBar

到目前为止,我提出的最佳解决方案是:

function addBar(foo: Foo): FooBar {
  const fooBar: FooBar = { ...foo, bar: 10 }
  return fooBar
}

创建对象的副本并依赖于rest属性。或者这个:

function addBar(foo: Foo): FooBar {
  const fooBar: FooBar = (foo: any)
  fooBar.bar = 10
  return fooBar
}

需要一些hacky cast。

理论上,这应该是可以实现的,无需任何铸造或复制。但Flow的动态分析可以检测到这一点吗?还有其他方法更适合这种用例吗?

1 个答案:

答案 0 :(得分:0)

您的问题在于foo对象字面值,除非特别注释,否则它不会支持其他突变。

为了进一步简化您的示例,以下内容将引发流错误:

const hello = { hello: 'hello' };
hello.world = 'world';

18: hello.world = 'world';
          ^ property `world`. Property not found in
18: hello.world = 'world';
    ^ object literal

但以下情况不会:

const hello: { hello: 'hello', [someOtherKey: string]: mixed };
hello.world = 'world';

// no errors!

但是,允许"property variance"有效地解封hello并将其转换为地图,如果您不想添加属性,则将其打开为静默类型错误。

另一种注释方法的简单方法是执行以下操作:

type FooBarType = {
  foo: mixed,
  bar?: number
}

function addBar(foo: FooBarType): FooBarType {
  foo.bar = 10;
  return foo;
}

addBar({ foo: 'hello' }); // no errors!

这确保了foo的类型可以支持添加bar。这与实际拥有该属性不同。您通常不希望您的方法绕过对象类型来改变它们的属性。相反,以能够支持突变的方式定义对象。否则使用函数方法,并返回一个新对象。以下内容可以让你保持密封:

function functionalAddBar(foo: Foo): FooBar {
  return Object.assign({}, foo, { bar: 10 });
}