【发布时间】:2020-08-12 06:07:13
【问题描述】:
假设这段代码:
// base class:
class Pin<Output, Input=Output> {
to<Out>(pin: Pin<Out, Output>): Pin<Out, Output> {
return pin;
}
from<In>(pin: Pin<Input, In>): Pin<Input, In> {
return pin;
}
}
//some type aliasing for convenience:
type SyncFunc<I, O> = (i: I) => O;
type Resolve<T> = SyncFunc<T, void>;
type AsyncFunc<I, O> = (i: I, cb: Resolve<O>) => void;
type Func<I, O> = SyncFunc<I, O> | AsyncFunc<I, O>;
function src<Type>(): Pin<Type> { return new Pin<Type>(); }
function map<I, O>(m: SyncFunc<I, O>): Pin<O, I>;
function map<I, O>(m: AsyncFunc<I, O>): Pin<O, I>;
function map<I, O>(m: SyncFunc<I, O> | AsyncFunc<I, O>): Pin<O, I> {
return new Pin<O, I>();
}
使用此设置,以下代码将出现错误:
src<number>().to(map((i, c: Resolve<number>) => c(i * 2))).to(map(x => x + 1));
由于i 的类型未正确推断。
我可以像这样改变重载的签名排列:
function map<I, O>(m: AsyncFunc<I, O>): Pin<O, I>;
function map<I, O>(m: SyncFunc<I, O>): Pin<O, I>;
function map<I, O>(m: SyncFunc<I, O> | AsyncFunc<I, O>): Pin<O, I> {
return new Pin<O, I>();
}
这解决了上一个示例的问题,但导致了这个问题:
src<number>().to(map(i => i * 2)).to(map(x => x + 1));
因为传递给map() 的函数现在假定为AsyncFunc 类型,返回类型未解析,因此x 假定为unknown 类型,这会导致另一个错误。
想在 Typescript 的 GitHub 上打开一个问题,但想到先在这里询问以确保我没有遗漏任何内容。这是预期的行为吗?即它是 Typescript 类型推断的错误,还是它当前缺少的功能,或者我错过了什么?
【问题讨论】:
-
你在这里使用重载是有原因的吗?这两个调用签名在参数数量或返回类型上没有区别,因此
<I, O>(m: Func<I, O>): Pin<O, I>类型的单个调用签名就足够了(与实现签名相同的类型)。我并不是说删除重载可以解决所有推理问题(你不能在推理泛型类型参数的同时依赖函数参数的推理),但它会使问题变得更简单。 -
不使用重载,所有推论都不起作用,即两个提到的错误都会发生。
-
你的意思是
i => i * 2?好吧,它并不真正匹配AsyncFunc<number, number>,因为它的返回类型不是 void(而是一个数字)。 -
我的意思是,
i => i * 2和x => x + 1都在里面,所以不管你怎么想。尝试写出const f: AsyncFunc<number, number> = i => i * 2,看看它如何不会导致错误。我之前评论中的两个链接解释了这一点;你看过他们吗?
标签: typescript typescript-typings type-inference typescript-generics typescript-types