dan*_*dan 21 constructor typescript
在JavaScript中,我可以定义一个构造函数,可以使用或不使用调用new:
function MyClass(val) {
if (!(this instanceof MyClass)) {
return new MyClass(val);
}
this.val = val;
}
Run Code Online (Sandbox Code Playgroud)
然后我可以MyClass使用以下任一语句构造对象:
var a = new MyClass(5);
var b = MyClass(5);
Run Code Online (Sandbox Code Playgroud)
我尝试使用下面的TypeScript类获得类似的结果:
class MyClass {
val: number;
constructor(val: number) {
if (!(this instanceof MyClass)) {
return new MyClass(val);
}
this.val = val;
}
}
Run Code Online (Sandbox Code Playgroud)
但是打电话MyClass(5)给了我错误Value of type 'typeof MyClass' is not callable. Did you mean to include 'new'?
有什么办法可以让这个模式在TypeScript中运行吗?
jca*_*alz 22
那这个呢?描述所需的形状MyClass及其构造函数:
interface MyClass {
val: number;
}
interface MyClassConstructor {
new(val: number): MyClass; // newable
(val: number): MyClass; // callable
}
Run Code Online (Sandbox Code Playgroud)
请注意,它MyClassConstructor被定义为可以作为函数调用并且可以作为构造函数使用.然后实现它:
const MyClass: MyClassConstructor = function(this: MyClass | void, val: number) {
if (!(this instanceof MyClass)) {
return new MyClass(val);
} else {
this!.val = val;
}
} as MyClassConstructor;
Run Code Online (Sandbox Code Playgroud)
以上作品,虽然有一些小皱纹.皱一:实现返回MyClass | undefined,编译器不知道的是,MyClass返回值对应于可调用的函数和undefined值对应于newable构造...所以它抱怨.因此as MyClassConstructor最后.皱纹二:this参数目前没有通过控制流分析缩小,所以我们必须声明在设置其属性时this不是这样,即使在那时我们知道它不可能.所以我们必须使用非null断言运算符.voidvalvoid!
无论如何,你可以验证这些工作:
var a = new MyClass(5); // MyClass
var b = MyClass(5); // also MyClass
Run Code Online (Sandbox Code Playgroud)
希望有所帮助; 祝好运!
警告:正如在@ Paleo的回答中所提到的,如果您的目标是ES2015或更高版本,class在您的源代码中使用将class在您编译的JavaScript中输出,并且根据规范要求 new().我见过像这样的错误TypeError: Class constructors cannot be invoked without 'new'.一些JavaScript引擎很可能忽略了规范,并且也很乐意接受函数式调用.如果您不关心这些警告(例如,您的目标明确是ES5,或者您知道您将在其中一个非规范的环境中运行),那么您肯定可以强制使用TypeScript:
class _MyClass {
val: number;
constructor(val: number) {
if (!(this instanceof MyClass)) {
return new MyClass(val);
}
this.val = val;
}
}
type MyClass = _MyClass;
const MyClass = _MyClass as typeof _MyClass & ((val: number) => MyClass)
var a = new MyClass(5); // MyClass
var b = MyClass(5); // also MyClass
Run Code Online (Sandbox Code Playgroud)
在这种情况下,你已经重命名MyClass了_MyClass,并且定义MyClass为一个类型(相同_MyClass)和一个值(与_MyClass构造函数相同,但其类型被声明为也可以像函数一样调用.)如上所示,在编译时工作.您的运行时是否满意它受上述警告的影响.就个人而言,我会坚持原始答案中的函数风格,因为我知道在es2015及更高版本中它们都是可调用的和可更新的.
祝你好运!
如果你只是想bindNew()从这个答案中寻找一种声明你的函数类型的方法,它需要一个符合规范class并产生像函数一样可以更新和可调用的东西,你可以这样做:
function bindNew<C extends { new(): T }, T>(Class: C & {new (): T}): C & (() => T);
function bindNew<C extends { new(a: A): T }, A, T>(Class: C & { new(a: A): T }): C & ((a: A) => T);
function bindNew<C extends { new(a: A, b: B): T }, A, B, T>(Class: C & { new(a: A, b: B): T }): C & ((a: A, b: B) => T);
function bindNew<C extends { new(a: A, b: B, d: D): T }, A, B, D, T>(Class: C & {new (a: A, b: B, d: D): T}): C & ((a: A, b: B, d: D) => T);
function bindNew(Class: any) {
// your implementation goes here
}
Run Code Online (Sandbox Code Playgroud)
这有正确输入这个的效果:
class _MyClass {
val: number;
constructor(val: number) {
this.val = val;
}
}
type MyClass = _MyClass;
const MyClass = bindNew(_MyClass);
// MyClass's type is inferred as typeof _MyClass & ((a: number)=> _MyClass)
var a = new MyClass(5); // MyClass
var b = MyClass(5); // also MyClass
Run Code Online (Sandbox Code Playgroud)
但要注意重载的声明bindNew()不适用于所有可能的情况.具体来说,它适用于最多需要三个参数的构造函数.具有可选参数或多个过载签名的构造函数可能无法正确推断.因此,您可能需要根据用例调整输入.
好了,希望这有助于.祝你好运第三次.
TypeScript 3.0 在休息和传播位置引入了元组,允许我们轻松处理任意数量和类型的参数的函数,而不需要上述重载和限制.这是以下的新声明bindNew():
declare function bindNew<C extends { new(...args: A): T }, A extends any[], T>(
Class: C & { new(...args: A): T }
): C & ((...args: A) => T);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
14031 次 |
| 最近记录: |