我有以下界面:
interface Functor<T> {
map <T1>(f: (x: T) => T1): Functor<T1>
}
interface Maybe<T> extends Functor<T> {}
接下来,我有map
函数实现,它需要Functor
并调用它.map
方法:
function map<T, U>(f: (x: T) => U, a: Functor<T>): Functor<U>
function map(f, a) {
return a.map(f);
}
如果我将此map
函数与Maybe
一起使用,则返回类型将为Functor<T>
而不是Maybe<T>
:
// type is Maybe<number>
const mb = new Just(5);
// type is Functor<string>, but should be Maybe<string>
const result = map((x) => 'str', mb)
我可以通过向map
函数添加额外的重载来解决这个问题:
function map<T, U>(f: (x: T) => U, a: Maybe<T>): Maybe<U>
但问题是Functor
和Maybe
类型位于不同的npm包中,map
函数实现对Maybe
一无所知。
我怎么能实现这个目标?
答案 0 :(得分:2)
TypeScript当前(截至2.4)缺少higher kinded types,这正是您正确表达a
参数与返回值之间关系所需的内容。例如,如果TypeScript允许泛型类型参数本身是通用的,您可以这样说:
function map<T, U, F<X> extends Functor<X>>(f: (x: T) => U, a: F<T>): F<U> {...}
(使用我刚编写的F<X>
符号)或:
function map<T, U, F extends Functor>(f: (x: T) => U, a: F<T>): F<U> {...}
(以您目前无法做到的方式使用裸Functor
)。
然后编译器可能会自动推断Maybe
的{{1}}。
如果您认为自己的用例足够引人注目,则可能需要转到the relevant GitHub issue,并通过提供或至少提供顶级帖子来表明您的支持。
正如@Stephan指出的那样,实际上并没有比你目前所做的更好的解决方法。我偶尔尝试用非语言足够的语言实现仿函数等,最终会转变为手动类型注释和未经检查的类型断言。我主要建议放弃☹️并仅实现您需要的特定仿函数,而不是试图对它们进行抽象。
希望有所帮助。祝你好运。