原型构造函数和工厂函数的Typescript

时间:2018-01-30 11:05:46

标签: typescript

我正在尝试使用构造函数和工厂函数来修改Typescript,但是当我通过tsc运行时,我仍然遇到以下错误。

src/tests/lib/mockNconf.ts(16,14): error TS2322: Type '(conf: Conf) => MockNconf' is not assignable to type 'MockNconfConstructor'.
  Type '(conf: Conf) => MockNconf' provides no match for the signature 'new (conf: Conf): MockNconf'.
src/tests/lib/mockNconf.ts(18,12): error TS2350: Only a void function can be called with the 'new' keyword.

我查看了How to define a Typescript constructor and factory function with the same name?,但这只涉及了typescript定义(使用纯javascript实现)。

我的代码是

import * as deepclone from 'lodash.clonedeep';

type Conf = { [key: string]: any };

interface MockNconf {
  set(key: string, data: any): void,
  get(key: string): any,
  clone(): MockNconf
}

interface MockNconfConstructor {
  new (conf: Conf): MockNconf;
  (conf: Conf): MockNconf;
}

export const MockNconf: MockNconfConstructor = function MockNconf(conf: Conf): MockNconf {
  if (!(this instanceof MockNconf)) {
    return new MockNconf(conf);
  }

  this.conf = conf;
};

Object.assign(MockNconf.prototype, {
  set: function set(key: string, data: any): void {
    if (typeof data === 'undefined') {
      if (typeof this.conf[key] !== 'undefined') {
        delete this.conf[key];
      }
    } else {
      this.conf[key] = data;
    }
  },
  get: function get(key: string): any {
    return this.conf[key];
  },
  clone: function clone(): MockNconf {
    const newConf = deepclone(this.conf);

    return new MockNconf(newConf);
  }
});

export default MockNconf;

In playground

2 个答案:

答案 0 :(得分:1)

感谢Titian Cernicova-Dragomir帮助解决问题。它可以在不使用类的情况下完成,但是MockNconf在首次定义时不能被强制转换,而是在构造函数中使用它时以及在导出它时需要进行转换。 / p>

import * as deepclone from 'lodash.clonedeep';

type Conf = { [key: string]: any };

interface MockNconfInterface {
  set(key: string, data: any): void,
  get(key: string): any,
  clone(): MockNconfInterface
}

interface MockNconfConstructor {
  new (conf: Conf): MockNconfInterface;
  (conf: Conf): MockNconfInterface;
}

const MockNconf = function MockNconf(conf: Conf): MockNconfInterface {
  if (!(this instanceof MockNconf)) {
    return new (<MockNconfConstructor>MockNconf)(conf);
  }

  this.conf = conf;
};

Object.assign(MockNconf.prototype, {
  set: function set(key: string, data: any): void {
    if (typeof data === 'undefined') {
      if (typeof this.conf[key] !== 'undefined') {
        delete this.conf[key];
      }
    } else {
      this.conf[key] = data;
    }
  },
  get: function get(key: string): any {
    return this.conf[key];
  },
  clone: function clone(): MockNconfInterface {
    const newConf = deepclone(this.conf);

    return new (<MockNconfConstructor>MockNconf)(newConf);
  }
});

export default MockNconf as MockNconfConstructor;

答案 1 :(得分:0)

没有办法在typescript中定义一个既可以作为类又可以作为函数的类/函数。但是,我们可以使用所有必需的方法对常规类进行decalare,并使用类型断言将其导出为MockNconfConstructor。该类由构造函数表示,因此构造函数将被调用,我们可以使用相同的代码(this instanceof MockNconf)来检查调用是作为构造函数还是作为常规函数发生的:

class MockNconf {
    conf: { [key: string]: any; };
    constructor(conf: Conf) {
        if (!(this instanceof MockNconf)) {
            return new MockNconf(conf);
        }

        this.conf = conf;
    }
    set(key: string, data: any): void {
        if (typeof data === 'undefined') {
            if (typeof this.conf[key] !== 'undefined') {
                delete this.conf[key];
            }
        } else {
            this.conf[key] = data;
        }
    }
    get(key: string): any {
        return this.conf[key];
    }
    clone(): MockNconf {
        const newConf = deepclone(this.conf);

        return new MockNconf(newConf);
    }
}


export default MockNconf as MockNconfConstructor;

用法:

import MockNconf from './q48519886';
var foo = MockNconf({ a: 10});
var boo = new MockNconf({a: 10});