在 Flow 中输入 "camel caser":方差问题?
Typing a "camel caser" in Flow: variance issues?
我一直在输入一个 "camel caser" 函数(一个使用 JSON 和驼峰式大小写它的键的函数)。一路上我 运行 遇到了一些问题,我很好奇你们是否有任何建议。
camel caser 从不改变其参数的形式,所以我想保留我传入的任何类型;理想情况下,在一个数字数组上调用 camelize
会 return 另一个数字数组,等等
我从以下开始:
type JSON = null | string | number | boolean | { [string]: JSON } | JSON[]
function camelize<J: JSON>(json: J): J {
throw "just typecheck please"
}
这对于简单的情况非常有效,null
、string
、number
和 boolean
,但对于 JSON 字典或数组。例如:
const dictionary: { [string]: number } = { key: 123 }
const camelizedDictionary = camelize(dictionary)
将因类型错误而失败。如果您传入一个值,例如键入 number[]
,则会出现类似的问题。我想我理解这个问题:数组和字典是可变的,因此它们指向的值的类型是不变的;数字数组 不是 JSON[]
的子类型,因此 Flow 会抱怨。如果数组和字典是协变的,我相信这种方法会奏效。
虽然它们不是协变的,但你们对我应该如何考虑这个问题有什么建议吗?
使用属性方差来解决你的字典问题:
type JSON = null | string | number | boolean | { +[string]: JSON } | JSON[]
https://flowtype.org/blog/2016/10/04/Property-Variance.html
至于 Arrays
的问题,正如您指出的那样,问题出在可变性上。不幸的是 Array<number>
不是 Array<JSON>
的子类型。我认为获得所需内容的唯一方法是明确枚举所有允许的 Array
类型:
type JSON = null | string | number | boolean | { +[string]: JSON } | Array<JSON> | Array<number>;
我在这里添加 Array<number>
来说明我的观点。显然这很麻烦,特别是如果您还想包含 JSON 元素的任意组合(如 Array<string | number | null>
)。但它有望解决常见问题。
(我也改成我比较熟悉的数组语法,但功能上应该没有区别)
有人说要添加 Array
的只读版本,这类似于协变对象类型,我相信它会解决您的问题。但到目前为止还没有任何结果。
根据您给出的内容完成tryflow。
Flow 现在支持 $ReadOnly
and $ReadOnlyArray
,因此另一种方法是将 JSON
类型定义为
type JSON =
| null
| string
| number
| boolean
| $ReadOnly<{ [string]: JSON }>
| $ReadOnlyArray<JSON>
这解决了上述问题之一,因为 $ReadOnlyArray<number>
是 $ReadOnlyArray<JSON>
的子类型。
根据 camelize
函数的实现,这可能不起作用,因为它可能会将键修改为驼峰式。但是,了解 Flow 中的只读实用程序是件好事,因为它们功能强大并且允许使用更简洁且可能更正确的函数类型。
我一直在输入一个 "camel caser" 函数(一个使用 JSON 和驼峰式大小写它的键的函数)。一路上我 运行 遇到了一些问题,我很好奇你们是否有任何建议。
camel caser 从不改变其参数的形式,所以我想保留我传入的任何类型;理想情况下,在一个数字数组上调用 camelize
会 return 另一个数字数组,等等
我从以下开始:
type JSON = null | string | number | boolean | { [string]: JSON } | JSON[]
function camelize<J: JSON>(json: J): J {
throw "just typecheck please"
}
这对于简单的情况非常有效,null
、string
、number
和 boolean
,但对于 JSON 字典或数组。例如:
const dictionary: { [string]: number } = { key: 123 }
const camelizedDictionary = camelize(dictionary)
将因类型错误而失败。如果您传入一个值,例如键入 number[]
,则会出现类似的问题。我想我理解这个问题:数组和字典是可变的,因此它们指向的值的类型是不变的;数字数组 不是 JSON[]
的子类型,因此 Flow 会抱怨。如果数组和字典是协变的,我相信这种方法会奏效。
虽然它们不是协变的,但你们对我应该如何考虑这个问题有什么建议吗?
使用属性方差来解决你的字典问题:
type JSON = null | string | number | boolean | { +[string]: JSON } | JSON[]
https://flowtype.org/blog/2016/10/04/Property-Variance.html
至于 Arrays
的问题,正如您指出的那样,问题出在可变性上。不幸的是 Array<number>
不是 Array<JSON>
的子类型。我认为获得所需内容的唯一方法是明确枚举所有允许的 Array
类型:
type JSON = null | string | number | boolean | { +[string]: JSON } | Array<JSON> | Array<number>;
我在这里添加 Array<number>
来说明我的观点。显然这很麻烦,特别是如果您还想包含 JSON 元素的任意组合(如 Array<string | number | null>
)。但它有望解决常见问题。
(我也改成我比较熟悉的数组语法,但功能上应该没有区别)
有人说要添加 Array
的只读版本,这类似于协变对象类型,我相信它会解决您的问题。但到目前为止还没有任何结果。
根据您给出的内容完成tryflow。
Flow 现在支持 $ReadOnly
and $ReadOnlyArray
,因此另一种方法是将 JSON
类型定义为
type JSON =
| null
| string
| number
| boolean
| $ReadOnly<{ [string]: JSON }>
| $ReadOnlyArray<JSON>
这解决了上述问题之一,因为 $ReadOnlyArray<number>
是 $ReadOnlyArray<JSON>
的子类型。
根据 camelize
函数的实现,这可能不起作用,因为它可能会将键修改为驼峰式。但是,了解 Flow 中的只读实用程序是件好事,因为它们功能强大并且允许使用更简洁且可能更正确的函数类型。