是否可以在打字稿类型定义中嵌套泛型?

时间:2016-06-17 10:01:50

标签: generics typescript functional-programming polymorphism

我想定义一个map函数,它可以泛化任何容器。无论是数组,还是流,或者是可观察的,还是任何旧的monad等。 我认为为了对此进行建模,我需要某种形式的嵌套泛型。这样我就可以定义<T<U>>

let f : (
    fn: (a:number) => string,
    list:number[]     
) => string[]

var toFixed = (a=0) => a.toFixed(2)
var list = [1,2,3]

f( toFixed , list ) //=> string[] ✓

// but what if I want to make the array's generic?
let f2 : <T,U>(
    fn: (a:T) => U,
    list:T[]     
) => U[]

// that's simple
f2(toFixed, list) //=> string[] ✓

// but how do you support generic *containers*?
// so that instead of an array, its an Observable, or
// any Monad or Functor?

let f3 : <T,U, V> (
    fn: (a:T) => U,
    container: V<T>
) => V<U> 

interface Observable <T> {}
interface Maybe <T> {}
interface Future<T> {}

let observable : Observable<number>
let maybe : Maybe<number>
let future : Future<number> 


f3(toFixed, observable) // => any ✖
// We want it to be: Observable<string>

f3(toFixed, maybe) // => any ✖
// We want it to be: Maybe<string>

f3(toFixed, future) // => any ✖
// We want it to be: Future<string>

f3(toFixed, [1,2,3]) // => any ✖
// We want it to be: string[]

如果有另一种方法来模拟这种行为,我想听听任何替代方案。

1 个答案:

答案 0 :(得分:0)

不完全是,但是您可以这样创建一个中间类型:

type Mappable<T> = {
    map: <U>(fn: (t: T) => U) => Mappable<U>;
};

type map = <A, B>(fn: (a: A) => B) => (m: Mappable<A>) => Mappable<B>;

const map: map = (fn) => (m) => m.map(fn);

这样做会丢失一些类型信息(流/数组都将以可映射的形式出现),但是如果要泛型映射的类型有限,则可以通过推断或并集类型克服这种情况扩展可映射。