鉴于类是从非类扩展而来的(包括但不限于函数),
function Fn() {}
class Class extends Fn {
constructor() {
super();
}
}
后果是什么?规范对此有何规定?
看起来 Babel、Google V8 和 Mozilla Spidermonkey 的当前实现都可以,而 TypeScript 会抛出
Type '() => void' is not a constructor function type
如果这是一个有效的 ES2015 代码,在 TypeScript 中处理它的正确方法是什么?
最佳答案
TypeScript 部分
到目前为止,spec说extends
子句后面必须跟一个 TypeReference。还有一个TypeReference必须采用 A.B.C<TypeArgument>
的形式, 比如 MyModule.MyContainer<MyItem>
.因此,从语法上讲,您的代码是正确的。但这不是打字大小写。
规范说 BaseClass
必须是有效的 typescript 类。然而,规范已过时,如前所述 here .现在 TypeScript 允许在 extends 子句中使用表达式,只要表达式被计算为构造函数即可。这个定义是基于实现的。可以看看here .简单地说,如果一个表达式实现了new() {}
,它就可以算作构造函数。界面。
ES2015部分
因此,您的问题是普通函数在 TypeScript 中未被识别为构造函数,这是有争议的,因为 ES2015 规范仅要求对象具有 [[construct]]
。内部方法。而用户定义的函数对象确实有它。
ES2015需要 BaseClass
is a constructor在运行时。一个对象 isConstructor
如果它有 [[construct]]
internal methd .规范说 [[construct]]
是 Function Object 的内部方法.用户函数是 Function Objects
的实例,所以它们自然是构造函数。但是builtin function和 arrow function可以没有[[construct]]
.
例如,下面的代码会在运行时抛出TypeError
因为parseInt
是内置函数,没有 [[construct]]
new parseInt()
// TypeError: parseInt is not a constructor
来自 ECMAScript
Arrow functions are like built-in functions in that both lack .prototype and any [[Construct]] internal method. So new (() => {}) throws a TypeError but otherwise arrows are like functions:
根据经验,任何没有 prototype
的函数不是 new
-能够。
变通
简而言之,并非每个函数都是构造函数,TypeScript 通过要求 new() {}
来捕获这一点.但是,用户定义的函数是构造函数。
要解决这个问题,最简单的方法是声明 Fn
作为一个变量,并将其转换为构造函数。
interface FnType {}
var Fn: {new(): FnType} = (function() {}) as any
class B extends Fn {}
不兼容的原因
DISCALIMER:我不是 TypeScript 核心贡献者,只是一个 TS 粉丝,有几个与 TS 相关的副项目。所以这部分是我个人的猜测。
TypeScript 是一个起源于 2012 的项目,当 ES2015 还在昏暗的黑暗中若隐若现的时候。 TypeScript 没有很好的类语义引用。
那时,main goal TypeScript 的主要目的是保持与 ES3/5 的兼容。所以,new
调用函数在 TypeScript 中是合法的,因为它在 ES3/5 中也是合法的。同时,TypeScript 也旨在捕获编程错误。 extends
一个函数可能是一个错误,因为该函数可能不是一个合理的构造函数(比如,一个仅用于副作用的函数)。 extends
在 ES3/5 中甚至不存在!所以 TypeScript 可以自由定义自己对 extends
的用法, 制作 extends
必须与 class
配对多变的。这使得 TypeScript 更 TypeSafe,同时与 JavaScript 兼容。
现在,ES2015 规范已经定稿。 JavaScript 也有一个 extends
关键词!然后不兼容来了。有efforts解决不兼容问题。然而,问题仍然存在。 () => void
或 Function
由于内置函数,类型不应扩展,如上所述。以下代码将中断
var a: (x: string) => void = eval
new a('booom')
另一方面,如果 ConstructorInterface
被引入 TypeScript 并且每个函数文字都实现了它,然后就会出现向后不兼容。以下代码现在可以编译,但不会在 ConstructorInterface
时编译被介绍
var a = function (s) {}
a = parseInt // compile error because parseInt is not assignable to constructor
当然,TS 团队可以有一个平衡这两个选项的解决方案。但这不是一个高优先级。此外,如果 salsa,TS 支持的 JavaScript 的代号,已完全实现。这个问题自然就解决了。
关于javascript - 从非类继承 ES6/TS 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34576731/