联盟类型和" currying" /部分应用程序样式API

时间:2016-04-25 23:56:18

标签: typescript

我有以下界面:

interface IFactory<T> extends Function {
    (...args: any[]): (((...args: any[]) => T)|T);
}

以下代码段会导致错误:

  

ts]输入&#39;((... args:any [])=&gt; IKatana)| IKatana&#39;不能分配给&#39; IKatana&#39;。输入&#39;(... args:any [])=&gt; IKatana&#39;不能分配给&#39; IKatana&#39;。财产&#39;击中&#39;类型&#39;(... args:any [])=&gt; IKatana&#39 ;.   (财产)NinjaWithUserDefinedFactory._katana:IKatana

@injectable()
class NinjaWithUserDefinedFactory implements INinja {

    private _katana: IKatana;
    private _shuriken: IShuriken;

    public constructor(
        @inject("IFactory<IKatana>") katanaFactory: IFactory<IKatana>,
        @inject("IShuriken") shuriken: IShuriken
    ) {
        this._katana = katanaFactory(); // error!
        this._shuriken = shuriken;
    }

    public fight() { return this._katana.hit(); };
    public sneak() { return this._shuriken.throw(); };

}

有时可以使用配置多次调用工厂。这也会导致问题:

  

无法调用类型缺少调用签名的表达式。

class Engine {
    constructor(type: string, cc: number) {}
}


let engineFactory: IFactory<Engine> = (type: string) => (cc: number) => {
    return new Engine(type, cc);
};

let dieselEngine = engineFactory("diesel");
let dieselEngine300cc = dieselEngine(300); // error!
let dieselEngine320cc = dieselEngine(320); // error!

关于如何克服这个问题的任何想法?

更新

打字稿团队正在研究Variadic Kinds,这将解决这个问题。

1 个答案:

答案 0 :(得分:2)

在以下签名中,您有:

interface IFactory<T> extends Function {
    (...args: any[]): (((...args: any[]) => T)|T);
}

更简单的版本是:

interface IFactory<T> {
    (...args: any[]): (IFactory<T>|T);
}

你基本上说调用IFactory的实例可以给你另一个工厂或T

如果dieselEngineIFactory ,那么并不能保证调用它会提供T或其他IFactory。编译器而言。因此,使用dieselEngine(foo)的结果作为函数是一个错误:

engineFactory("diesel")(300); // Error

修复

从上面的分析中可以清楚地看出,您需要指定前面的呼叫次数。您可以将其简化为2个呼叫工厂:

interface IFactory<T,C> {
    (type:string): (configuration:C) => T;
}

class Engine {
    constructor(type: string, cc: number) {}
}


let engineFactory: IFactory<Engine,number> = (type: string) => (cc: number) => {
    return new Engine(type, cc);
};

let dieselEngine = engineFactory("diesel");
let dieselEngine300cc = dieselEngine(300); // Okay!
let dieselEngine320cc = dieselEngine(320); // Okay!