在@flow strict下,实用程序功能可以使用Object的哪些替代方法?

时间:2018-11-15 15:16:31

标签: javascript node.js flowtype strict

我有兴趣将我的Flow代码切换为project.clj类型检查,但是我有一些通用的对象处理底层工具,例如:

strict

由于在严格模式下不允许使用Object类型,因此如何为明确应该在任何通用Object上运行的函数声明类型?

2 个答案:

答案 0 :(得分:4)

在这种情况下,实际上您将从严格的键入中受益匪浅。通过使用Object,您实际上将关闭所有通过这些函数的数据的键入系统 ,直到可以在其他位置显式重新键入它们为止。这意味着您当前正在丢失大量不需要的键入信息。

这是泛型的教科书案例,已记录在here中。

// @flow strict
const hasKey = <T: {}>(o: T): (string => boolean) =>
  Object.prototype.hasOwnProperty.bind(o);

const union = <T: {}>(objects: Array<T>): T =>
  objects.reduce((acc, o) => ({ ...acc, ...o }), ({}: $Shape<T>));

上面最重要的部分是: {}中的<T: {}>。这些是类型范围。如果泛型是一种说法,即“允许用户传递他们想要的任何类型,并将该类型存储在变量中,以便我以后可以引用它”,那么 bounds 类型是一种说法,“允许用户传递他们想要的任何类型,只要该类型是X类型的成员。”

由于width subtyping的工作方式,{}是最通用的对象类型。实际上,所有对象都是{}的子类型。所以<T: {}>的基本含义是,“ T应该是作为对象的任何类型。”

请注意,这与<T: Object>有很大不同,这基本上意味着:“ T是一个对象,从现在开始,我将不再检查它。”这意味着我们可以执行以下操作:

const o: Object = {};
console.log(o.some.member.that.doesnt.exist); // no error at compile time,
                                              // but obvious error at runtime

不一样:

const o: {} = {};
console.log(o.member); // Error, we don't know about this member property!

因此,通过告诉流程该参数是{}的子类型,我们告诉它它具有对象的基本API。它具有属性,可以休息和散布,可以进行字符串索引等,但是别无其他。此外,通过将数据类型存储为通用T并返回该类型,我们正在维护参数的类型信息。这意味着无论我们传入什么参数,都将在另一端得到相同类型的东西(而不是神秘的黑盒子)。

答案 1 :(得分:0)

也许您可以使用流泛型编写函数。例如,

function union <T>(os: Array<T>): T { 
   ...
}

文档:https://flow.org/en/docs/types/generics/