Arrays typescript中递归函数中嵌套数组的正确类型
我正在尝试实现一个函数Arrays typescript中递归函数中嵌套数组的正确类型,arrays,typescript,recursion,types,Arrays,Typescript,Recursion,Types,我正在尝试实现一个函数flattedeep,它与typescript中的lodash非常相似,但是我在类型定义方面遇到了一些问题,下面是我的代码: 导出接口DeepArray扩展数组{} 导出常量flattedeep=(数组:DeepArray):T[]=>{ 返回[].concat(…array.map(arr=>{ if(数组isArray(arr)){ 返回深度(arr) }否则{ 返回arr } })) } Flattedeep([1[2[3[4]],5]])//应该返回[1,2,3,4
flattedeep
,它与typescript中的lodash非常相似,但是我在类型定义方面遇到了一些问题,下面是我的代码:
导出接口DeepArray扩展数组{}
导出常量flattedeep=(数组:DeepArray):T[]=>{
返回[].concat(…array.map(arr=>{
if(数组isArray(arr)){
返回深度(arr)
}否则{
返回arr
}
}))
}
Flattedeep([1[2[3[4]],5]])//应该返回[1,2,3,4,5]
到目前为止,它看起来不错,当我测试它时,功能本身是正常的,但是flattedeep()
函数推断出错误的返回类型:
const arr=[1,2,3,4,5]]
常数展平DARR=展平深度(arr)
//推断类型为:
//常数展平DARR:(数字|(数字|)(数字|数字[])[])[])[]))[]
//但它应该是数字[]或数组?因为最终的结果是一维数组
那么我如何解决这个问题来提供正确的类型呢?问题在于,由于
DeepArray
是递归类型,并且在结构上与(T | DeepArray)[
相同,因此没有唯一的T
对应于DeepArray
。例如,类型DeepArray
与(数字| DeepArray)[
兼容,因此与(数字|(数字| DeepArray)[])[]
兼容
因此,当编译器试图为某些T
将(number | number[])[]
等类型解释为DeepArray
时,不能保证推断number
。它完全可以自由选择number | number[]
,或者number |(number | number[])[]
,或者各种各样的东西,只要它为T
选择的任何东西允许(number | number[])[
与DeepArray
兼容。因此,即使flattedeep()
的实现确实使值变平,您也不能指望推理来“展平”t
:
declare const flattenDeepOrig: <T>(array: DeepArray<T>) => T[]
const oops = flattenDeepOrig([1, [2, [3, [4]], 5]])
// const oops: (number | (number | (number | number[])[])[])[]
但你可能想让编译器帮你解决这个问题。要做到这一点,最好使用像(array:T[])=>flattarray[]
这样的类型,用于一些适当的flattarray
定义,该定义将深度嵌套的数组类型显式折叠为平面类型。这是因为给定一个值[1,2,3,4,5]
作为T[]
,T
唯一合理的推理候选值是类似于number |(number |(number | number[])[]
,此时您希望flattarray
将其显式展平到number
。所以我们只需要定义flattarray
不幸的是,
flattarray
的直接定义是循环的,编译器不支持:
type FlattenArrayOops<T> = T extends Array<any> ? FlattenArrayOops<T[number]> : T; // error!
// ~~~~~~~~~~~~~~~~ <-- Type alias 'FlattenArrayOops' circularly references itself.
type flattarrayops=T扩展了数组,以允许这种循环类型,但目前还没有官方支持的方法来实现这种行为
在这种情况下,我通常会通过手动“展开”定义,将其转换为一个固定深度的版本,来近似圆形类型,如下所示:
type FlattenArray<T> = T extends Array<any> ? FA0<T[number]> : T;
type FA0<T> = T extends Array<any> ? FA1<T[number]> : T;
type FA1<T> = T extends Array<any> ? FA2<T[number]> : T;
type FA2<T> = T extends Array<any> ? FA3<T[number]> : T;
type FA3<T> = T extends Array<any> ? FA4<T[number]> : T;
type FA4<T> = T extends Array<any> ? FA5<T[number]> : T;
type FA5<T> = T extends Array<any> ? FA6<T[number]> : T;
type FA6<T> = T extends Array<any> ? FA7<T[number]> : T;
type FA7<T> = T extends Array<any> ? FA8<T[number]> : T;
type FA8<T> = T extends Array<any> ? FAX<T[number]> : T;
type FAX<T> = T; // bail out
type flattarray=T extensed Array问题在于,由于DeepArray
是递归类型的,并且在结构上与(T | DeepArray)[
相同,因此没有唯一的T
对应于DeepArray
。例如,类型DeepArray
与(数字| DeepArray)[
兼容,因此与(数字|(数字| DeepArray)[])[]
兼容
因此,当编译器试图为某些T
将(number | number[])[]
等类型解释为DeepArray
时,不能保证推断number
。它完全可以自由选择number | number[]
,或者number |(number | number[])[]
,或者各种各样的东西,只要它为T
选择的任何东西允许(number | number[])[
与DeepArray
兼容。因此,即使flattedeep()
的实现确实使值变平,您也不能指望推理来“展平”t
:
declare const flattenDeepOrig: <T>(array: DeepArray<T>) => T[]
const oops = flattenDeepOrig([1, [2, [3, [4]], 5]])
// const oops: (number | (number | (number | number[])[])[])[]
但你可能想让编译器帮你解决这个问题。要做到这一点,最好使用像(array:T[])=>flattarray[]
这样的类型,用于一些适当的flattarray
定义,该定义将深度嵌套的数组类型显式折叠为平面类型。这是因为给定一个值[1,2,3,4,5]
作为T[]
,T
唯一合理的推理候选值是类似于number |(number |(number | number[])[]
,此时您希望flattarray
将其显式展平到number
。所以我们只需要定义flattarray
不幸的是,flattarray
的直接定义是循环的,编译器不支持:
type FlattenArrayOops<T> = T extends Array<any> ? FlattenArrayOops<T[number]> : T; // error!
// ~~~~~~~~~~~~~~~~ <-- Type alias 'FlattenArrayOops' circularly references itself.
type flattarrayops=T扩展了数组,以允许这种循环类型,但目前还没有官方支持的方法来实现这种行为
在这种情况下,我通常会通过手动“展开”定义,将其转换为一个固定深度的版本,来近似圆形类型,如下所示:
type FlattenArray<T> = T extends Array<any> ? FA0<T[number]> : T;
type FA0<T> = T extends Array<any> ? FA1<T[number]> : T;
type FA1<T> = T extends Array<any> ? FA2<T[number]> : T;
type FA2<T> = T extends Array<any> ? FA3<T[number]> : T;
type FA3<T> = T extends Array<any> ? FA4<T[number]> : T;
type FA4<T> = T extends Array<any> ? FA5<T[number]> : T;
type FA5<T> = T extends Array<any> ? FA6<T[number]> : T;
type FA6<T> = T extends Array<any> ? FA7<T[number]> : T;
type FA7<T> = T extends Array<any> ? FA8<T[number]> : T;
type FA8<T> = T extends Array<any> ? FAX<T[number]> : T;
type FAX<T> = T; // bail out
type flattarray=T扩展数组