[英]Iterable<Iterable<T>> cannot confirm generic T in function
这是我的问题。
const iterable = [[[1,2,3]]]
function flat<T>(t:Iterable<Iterable<T>>):Iterable<T>{
return [...t][0]
}
const flatted = flat(iterable) //return Iterable<unknown>
以上 function 不能假设 T 为数字,只需将其断言为未知。 此时此刻,我坚持认为“嗯……不能推断出泛型中的泛型?”。 但是下面的代码卡盘效果很好
const iterable = [[[1,2,3]]]
function flat<T>(t:Array<Array<T>>):Array<T>{
return [...t][0]
}
const flatted = flat(iterable) // omg.. return Array<number>
还
const iterable = [[[1,2,3]]]
function flat<T>(t:Iterable<Array<T>>):Array<T>{
return [...t][0]
}
const flatted = flat(iterable) // also works.. return Array<number>
它们之间有什么区别? 感谢您阅读我的问题。
呸,是的,我看到默认推理不足以将Iterable<Iterable<T>>
展开到T
中。 如果您查看相关库中如何定义Iterable
的类型,这并不奇怪:
interface Iterable<T> {
[Symbol.iterator](): Iterator<T>;
}
Iterable<T>
有一个符号键控方法,其返回类型为Iterator<T>
,它本身定义为:
interface Iterator<T, TReturn = any, TNext = undefined> {
next(...args: [] | [TNext]): IteratorResult<T, TReturn>;
return?(value?: TReturn): IteratorResult<T, TReturn>;
throw?(e?: any): IteratorResult<T, TReturn>;
}
其中所有方法都返回IteratorResult<T, ...>
,它被定义为可区分的联合类型
type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
其成员是
interface IteratorYieldResult<TYield> {
done?: false;
value: TYield;
}
interface IteratorReturnResult<TReturn> {
done: true;
value: TReturn;
}
其中只有一个具有您要查找的相关类型T
的value
属性。
因此,要将Iterable<T>
的X
类型转换为T
,编译器需要执行类似Extract<ReturnType<ReturnType<X[I]>['next']>, { done?: false }>['value']
(其中I
是一个虚构的可索引[Symbol.iterator]
属性,由于 TypeScript; microsoft/TypeScript#24622中的错误,我们无法自己编写它)。
我认为可能存在一些深度限制,之后编译器会放弃尝试推断事物。 您可以看到从Iterable<T>
推断T
是可行的(可能大约有 5 或 6 层嵌套),但从Iterable<Iterable<T>>
推断T
太深了(10 或 12 层?):
type N = number[][] extends Iterable<infer T> ? T : never; // number[] 👍
type O = number[][] extends Iterable<Iterable<infer T>> ? T : never; // unknown 👎
这导致我采用以下解决方法:创建一个类型别名以显式操作一层Iterable
,然后使用它两次:
type DeIterable<T extends Iterable<any>> = T extends Iterable<infer U> ? U : never;
你可以看到这个作品:
type Okay = DeIterable<DeIterable<number[][]>>; // number 👍
现在flat()
可以这样定义:
function flat<II extends Iterable<Iterable<any>>>(
t: II
): Iterable<DeIterable<DeIterable<II>>> {
return [...t][0]
}
其中输入值是泛型类型II
,我们在其上使用DeIterable
两次以获得您之前想要的T
:
const flatted = flat(iterable) //return Iterable<number[]>
看起来不错,现在,好吧; 希望有帮助; 祝你好运!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.