【问题标题】: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 的返回类型是什么。

【问题讨论】:

标签: typescript visual-studio-code tuples typescript-generics


【解决方案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 手册中找到这些信息。
猜你喜欢
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-14
  • 1970-01-01
  • 2019-05-10
相关资源
最近更新 更多