Iterable<Iterable<T>>无法确认函数中的泛型T [英] Iterable<Iterable<T>> cannot confirm generic T in function

查看:0
本文介绍了Iterable<Iterable<T>>无法确认函数中的泛型T的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的问题。

const iterable = [[[1,2,3]]]
function flat<T>(t:Iterable<Iterable<T>>):Iterable<T>{
    return [...t][0]
}
const flatted = flat(iterable) //return Iterable<unknown>  
上面的函数不能假设T为数字,只能将其断言为未知。 此时此刻,我认为‘嗯……不能推断仿制药中的仿制药?’但在下面的代码中,Chuck运行良好

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的类型是defined in the relevant library

,这并不令人惊讶
interface Iterable<T> {
    [Symbol.iterator](): Iterator<T>;
}

anIterable<T>有一个带符号键的方法,其返回类型为Iterator<T>,其本身为definedas:

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, ...>,即defined为区分的联合类型

type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;

谁的members

interface IteratorYieldResult<TYield> {
    done?: false;
    value: TYield;
}

interface IteratorReturnResult<TReturn> {
    done: true;
    value: TReturn;
}

,其中只有一个具有您试图查找的相关类型的value属性。

因此,要将Iterable<T>的类型X转换为T,编译器需要执行类似Extract<ReturnType<ReturnType<X[I]>['next']>, { done?: false }>['value']的操作(其中I是一个虚构的可索引[Symbol.iterator]属性,由于类型脚本中的错误,我们不能自己编写该属性;microsoft/TypeScript#24622)。

我认为可能存在某个深度限制,超过该限制后,编译器将放弃尝试推断。您可以看到TIterable<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[]>  

现在看起来不错!好的,希望这会有帮助;祝你好运!

Playground link to code

这篇关于Iterable&lt;Iterable&lt;T&gt;&gt;无法确认函数中的泛型T的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆