为啥我的元组中的第一个值总是未知的?

Posted

技术标签:

【中文标题】为啥我的元组中的第一个值总是未知的?【英文标题】:Why is the first value in my Tuple always unknown?为什么我的元组中的第一个值总是未知的? 【发布时间】:2020-10-03 12:06:15 【问题描述】:

我的类型:

interface Pair<FirstValue, SecondValue> 
    first: () => FirstValue,
    second: () => SecondValue,
    toString: () => string


type StateRunner = <V, S>(state: S) => Pair<V, S>;

我的代码:

const Pair = <V1, V2>(v1, v2): Pair<V1, V2> => (
    first: () => v1,
    second: () => v2,
    toString: () => `Pair($v1, $v2)`
);

const myRunner: StateRunner = (state) => Pair("hello", state);

const result = myRunner(someString, someData);

在 VSCode 中,我得到了这个:

我 100% 肯定我只是不太了解泛型(我是 TypeScript 的新手),但我认为它会将结果列为:

Pair<string, 
    size: string,
    active: boolean
>

我错过了什么?我是否对 TypeScript/VSCode 期望过高?我感到困惑的主要原因是,当我直接使用Pair 时,智能感知完全知道firstsecond 的返回类型是什么。

【问题讨论】:

除了他的回答之外,这里是@jcalz本人对TypeScript ***.com/a/60179671/795876中泛型函数的返回类型的详尽解释:) 【参考方案1】:

除此之外:我发现自己必须更改您的示例代码才能到达您的问题所在的位置。示例:注释v1v2

const Pair = <V1, V2>(v1: V1, v2: V2): Pair<V1, V2> => (
  first: () => v1,
  second: () => v2,
  toString: () => `Pair($v1, $v2)`
);

myRunner 只接受一个参数:

const result = myRunner( a: "" ); 

我想这就是你的意思。


您的代码的问题是StateRunner 类型的函数声称能够获取调用者选择的泛型类型S 的值,并为泛型类型V 生成Pair&lt;V, S&gt;由调用者选择。这是不可能的,是吗?由于没有传入V 类型的值,因此没有合理的方式输出Pair&lt;V, S&gt;。这种情况的一个症状是,当您让编译器推断调用者将指定的类型时,它完全不知道V 将是什么。所以它推断unknown


查看您的实现,您希望调用者选择S,而实现者选择V。这意味着VS 不应该是同类的泛型。我希望StateRunner 本身是通用的,如下所示:

type StateRunner<V> = <S>(state: S) => Pair<V, S>;

所以VStateRunner 类型的一部分,由实现者选择,S 是通用函数类型的一部分,由调用者选择。而且你不会有StateRunner 类型的值;对于特定的V,您将拥有StateRunner&lt;V&gt; 类型的值。对于myRunner,它将是StateRunner&lt;string&gt;

const myRunnerAnnotated: StateRunner<string> = state => Pair("hello", state);

现在一切正常:

const r = myRunnerAnnotated( a: "" ); // Pair<string, a: string>

如果您不想手动将某些内容注释为StateRunner&lt;string&gt;,您可以使用辅助函数为您推断V

const asStateRunner = <V>(s: StateRunner<V>) => s;

并像这样使用它:

const myRunner = asStateRunner((state) => Pair("hello", state));
// const myRunner: StateRunner<string>

您可以看到myRunner 被推断为StateRunner&lt;string&gt;,然后result 像以前一样按照您想要的方式工作:

const result = myRunner( a: "" );  // Pair<string, a: string>

好的,希望对您有所帮助。祝你好运!

Playground link to code

【讨论】:

对于那些将来偶然发现这个问题的人来说,我从中学到的最有价值的一课是在函数名旁边声明的泛型(例如,myFunc)是为实现者而设的,并且在函数体旁边声明的泛型是给调用者的。那一点建议完全改变了我对 TypeScript 的理解。我不知道为什么我无法在 TypeScript 手册中找到这些信息。

以上是关于为啥我的元组中的第一个值总是未知的?的主要内容,如果未能解决你的问题,请参考以下文章

从Haskell中的元组中提取第n个元素(其中n和元组被赋予参数)

我的元组中的那些小“u”是啥? (python 2.7)[重复]

在 Python 元组列表中查找重复项

如何将元组列表转换为 pandas 数据框,以便每个元组的第一个值代表一列?

通过映射匹配元组中的值

从元组的元组中创建一个列表