我一直在阅读Tom Harding的关于幻想土地规范的博客系列,今天下午我正在玩打字稿中的仿函数。
class Just<T> {
private x: T
constructor (x: T) {
this.x = x
}
map <R>(f: (a: T) => R): Just<R> {
return new Just(f(this.x))
}
}
class Nothing<T> {
private x: T
constructor (_: T) {
// noop
}
map <R>(_: (a: T) => R): Nothing<R> {
return new Nothing<R>(undefined)
}
}
type Maybe<T> = Just<T> | Nothing<T>
const map1 = <T, R>(f: (a: T) => R, a: Maybe<T>): Maybe<R> => {
return a.map(f)
}
不幸的是,上面的a.map(f)
会导致以下编译时错误:
[ts] Cannot invoke an expression whose type lacks a call signature.
Type '(<R>(f: (a: T) => R) => Just<R>) | (<R>(_: (a: T) => R) => Nothing<R>)'
has no compatible call signatures.
我觉得这应该可以工作......我做了一个更简单的例子,它不是一个算子,但它以大多数相同的方式使用泛型:
class A<T> {
private x: T
constructor (x: T) {
this.x = x
}
func <R>(f: (a: T) => R): R { // this is returning R not A<R>
return f(this.x)
}
}
class B<T> {
constructor (_: T) {
//
}
func <R>(_: (a: T) => R): R {
return undefined
}
}
type C<T> = A<T> | B<T>
const func = <T, R>(f: (a: T) => R, a: C<T>): R => {
return a.func(f)
}
这段代码编译得很好。如果我将函数的返回类型更改为A<R>
和B<R>
(即,如果map返回C<R>
),那么我会得到与上面相同的错误。
所以我想知道:到底是什么?这是一些疯狂的逆变/协变的事吗?这是打字稿的预期行为吗?这只是我错过了什么吗? (或者它没什么^ o ^ //)。
编辑:我尝试使用继承而不是联合重新实现上述内容:
abstract class Maybe<T> {
protected x: T
constructor (x: T) {
this.x = x
}
abstract map <R>(f: (a: T) => R): Maybe<R>
}
class Just<T> extends Maybe<T> {
constructor (x: T) {
super(x)
}
map <R>(f: (a: T) => R): Just<R> {
return new Just(f(this.x))
}
}
class Nothing<T> extends Maybe<T> {
constructor (_: T) {
super(undefined)
}
map <R>(f: (a: T) => R): Nothing<R> {
return new Nothing(undefined)
}
}
const map2 = <T, R>(f: (a: T) => R, a: Maybe<T>): Maybe<R> => {
return a.map(f)
}
它工作得很好!什么给,打字稿!?
即使考虑到上述情况,这也不是我想要的。 Just
没有&#34;延伸&#34; Maybe
,Maybe
是Just
和Nothing
的联盟。这是我的高速公路方式
编辑:编辑:我使用Functor的接口再次尝试了
// tslint:disable-next-line:interface-name
interface Functor<T> {
map: <R>(f: (a: T) => R) => Functor<R>
}
class Just<T> implements Functor<T> {
private readonly x: T
constructor (x: T) {
this.x = x
}
map <R>(f: (a: T) => R): Just<R> {
return new Just(f(this.x))
}
}
class Nothing<T> implements Functor<T> {
constructor (_: T) {
// nop
}
map <R>(_: (a: T) => R): Nothing<R> {
return new Nothing(undefined)
}
}
type Maybe<T> = Functor<T>
const map3 = <T, R>(f: (a: T) => R, a: Maybe<T>): Maybe<R> => {
return a.map(f)
}
这也有效,而且我可以说实现Functor的界面,因为嗯......它确实如此。我对type Maybe<T> = Functor<T>
仍然不满意,因为它过度指定了类型(Functor的成员多于Maybe?)
另外,我猜地图不仅需要返回Functor,还需要相同的 Functor,就像Maybe的地图返回一个Maybe(不仅仅是任何Functor)。我开始明白为什么我们需要更高级的类型才能代表这种东西?
编辑:添加第二个通用帐户的类型的仿函数似乎工作。现在Just的地图必须返回Just。// tslint:disable-next-line:interface-name
interface Functor<K, T> {
map: <R>(f: (a: T) => R) => Functor<K, R>
}
然后我将Maybe定义为:
type Maybe<T> = Functor<Just<T> | Nothing<T>, T>
手指交叉。