javascript - 从非类继承 ES6/TS 类

标签 javascript typescript ecmascript-6

鉴于类是从非类扩展而来的(包括但不限于函数),

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 部分

到目前为止,specextends子句后面必须跟一个 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 functionarrow 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 配对多变的。这使得 TypeScriptTypeSafe,同时与 JavaScript 兼容。

现在,ES2015 规范已经定稿。 JavaScript 也有一个 extends关键词!然后不兼容来了。有efforts解决不兼容问题。然而,问题仍然存在。 () => voidFunction由于内置函数,类型不应扩展,如上所述。以下代码将中断

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/

相关文章:

javascript - TypeScript 中 Fat 箭头函数后的 "void = () => {}"是什么意思?

TypeScript - 在严格模式下安全、方便地使用字符串访问对象/映射值

基于枚举常量的 Typescript 排序

javascript - querySelectorAll 和appendChild 的组合不起作用

javascript - ES2015 Babel 字符串插值不适用于撇号(但适用于双引号)

javascript - Jquery引用错误: invalid assignment left-hand side

javascript - Angular 认证: Avoid multiple resolve for different routes

javascript - Closure 编译器导出 Typescript 类和函数

javascript - 调用具有多个参数的函数的更简单方法?

javascript - 在 mxgraph 中设置连接器(边缘)点