如何从 TypeScript 中的模板扩展抽象 class?
How to extends abstract class from template in TypeScript?
我有一个类似的架构,我想用一个模板扩展我的 TemplateService
,但实际上我有一个错误。有没有办法从模板扩展抽象 class?
// Error message
ReferenceError: Service is not defined
abstract class TemplateService<Service> extends Service
^
// My code
abstract class TemplateService<Service> extends Service { // Cannot find name 'Service'.
constructor() {
const name = "Hello world !";
super(name);
}
public getJob(): string {
return "Job";
}
protected getAge(): number {
return 25;
}
}
class ImportedService {
constructor(private _name: string) {}
public getName() {
return this._name;
}
}
class MyService extends TemplateService<ImportedService> {
constructor() {
super();
}
public fooMethod(): void {
...
}
}
写的是类别错误
abstract class TemplateService<Service> extends Service {}
TypeScript 的静态类型系统,包括实际运行的发出的 JavaScript 中的 generic type parameters, is erased。在上面,abstract
和 <Service>
是静态类型系统的一部分,而其余的 JavaScript 是有效的(至少对于 JavaScript 的现代版本)。您编写的代码将发出类似
的内容
class TemplateService extends Service {}
希望能说明问题所在。除非范围内碰巧有一个名为 Service
的 class 构造函数,否则这将是一个运行时错误。你不能 subclass a type;你需要子class一个构造函数值.
TypeScript 通过 mixins 的概念对 subclass 任意构造函数值提供了一些支持。不是将 TemplateService
写成 class,而是将其设为接受 class 构造函数作为输入的 class 工厂函数 。从概念上讲,它看起来像
// don't write this, it's not valid TS
function TemplateService<C extends new (name: string) => object>(ctor: C) {
return class extends ctor { // error!
// ------> ~~~~~
constructor() {
const name = "Hello world !";
super(name);
}
public getJob(): string {
return "Job";
}
protected getAge(): number {
return 25;
}
};
}
你会像这样使用它
class ImportedService {
constructor(private _name: string) { }
public getName() {
return this._name;
}
}
class MyService extends TemplateService(ImportedService) {
constructor() {
super();
}
public fooMethod(): void {
console.log(this.getName());
console.log(this.getJob());
console.log(this.getAge())
}
}
不幸的是,TypeScript 的 mixin 支持假定您将只传递构造函数参数,因此上面的 TemplateService
实现会产生编译器错误。关于这个有一些未解决的问题,例如 microsoft/TypeScript#37142. For now all I could say is to work around it by using several type assertions 欺骗编译器允许 mixin 并给它正确的类型。
对于此处的特定示例代码,它可能如下所示:
function TemplateService<C extends new (name: string) => object>(ctor: C) {
const c = class extends (ctor as new (...args: any) => object) {
constructor() {
const name = "Hello world !";
super(name);
}
public getJob(): string {
return "Job";
}
protected getAge(): number {
return 25;
}
};
return c as {
new(): InstanceType<C> & InstanceType<typeof c>;
}
}
现在编译器认为 TemplateService(ImportedService)
是一个 no-arg 构造函数,它生成 ImportedService
的组合(通过 intersection)和匿名 class 表达式与 getJob()
方法和 protected getAge()
方法。
我有一个类似的架构,我想用一个模板扩展我的 TemplateService
,但实际上我有一个错误。有没有办法从模板扩展抽象 class?
// Error message
ReferenceError: Service is not defined
abstract class TemplateService<Service> extends Service
^
// My code
abstract class TemplateService<Service> extends Service { // Cannot find name 'Service'.
constructor() {
const name = "Hello world !";
super(name);
}
public getJob(): string {
return "Job";
}
protected getAge(): number {
return 25;
}
}
class ImportedService {
constructor(private _name: string) {}
public getName() {
return this._name;
}
}
class MyService extends TemplateService<ImportedService> {
constructor() {
super();
}
public fooMethod(): void {
...
}
}
写的是类别错误
abstract class TemplateService<Service> extends Service {}
TypeScript 的静态类型系统,包括实际运行的发出的 JavaScript 中的 generic type parameters, is erased。在上面,abstract
和 <Service>
是静态类型系统的一部分,而其余的 JavaScript 是有效的(至少对于 JavaScript 的现代版本)。您编写的代码将发出类似
class TemplateService extends Service {}
希望能说明问题所在。除非范围内碰巧有一个名为 Service
的 class 构造函数,否则这将是一个运行时错误。你不能 subclass a type;你需要子class一个构造函数值.
TypeScript 通过 mixins 的概念对 subclass 任意构造函数值提供了一些支持。不是将 TemplateService
写成 class,而是将其设为接受 class 构造函数作为输入的 class 工厂函数 。从概念上讲,它看起来像
// don't write this, it's not valid TS
function TemplateService<C extends new (name: string) => object>(ctor: C) {
return class extends ctor { // error!
// ------> ~~~~~
constructor() {
const name = "Hello world !";
super(name);
}
public getJob(): string {
return "Job";
}
protected getAge(): number {
return 25;
}
};
}
你会像这样使用它
class ImportedService {
constructor(private _name: string) { }
public getName() {
return this._name;
}
}
class MyService extends TemplateService(ImportedService) {
constructor() {
super();
}
public fooMethod(): void {
console.log(this.getName());
console.log(this.getJob());
console.log(this.getAge())
}
}
不幸的是,TypeScript 的 mixin 支持假定您将只传递构造函数参数,因此上面的 TemplateService
实现会产生编译器错误。关于这个有一些未解决的问题,例如 microsoft/TypeScript#37142. For now all I could say is to work around it by using several type assertions 欺骗编译器允许 mixin 并给它正确的类型。
对于此处的特定示例代码,它可能如下所示:
function TemplateService<C extends new (name: string) => object>(ctor: C) {
const c = class extends (ctor as new (...args: any) => object) {
constructor() {
const name = "Hello world !";
super(name);
}
public getJob(): string {
return "Job";
}
protected getAge(): number {
return 25;
}
};
return c as {
new(): InstanceType<C> & InstanceType<typeof c>;
}
}
现在编译器认为 TemplateService(ImportedService)
是一个 no-arg 构造函数,它生成 ImportedService
的组合(通过 intersection)和匿名 class 表达式与 getJob()
方法和 protected getAge()
方法。