如何在Type Script中使用反射获取实现某个基类的子类? [英] How to get child classes which implement a certain base class using reflection in Type Script?

查看:72
本文介绍了如何在Type Script中使用反射获取实现某个基类的子类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们能否像 C# 一样在 Type Script 中使用反射来获取实现某个基类的类列表?

Can we use reflection in Type Script just like C# to get the list of classes which implement a certain base class?

例如,假设 Snake 和 Horse 实现了基类 Animal.现在我需要获取实现 Animal 的类.类似于我们在 C# 中可以做的:

For example, let say Snake and Horse implement the base class Animal. Now I need to get classes which implement Animal. Similar to what we can do in C#:

C# 等效代码:

var childTypes = assembly.GetTypes().Where(_ => _.IsSubclassOf(typeof(Animal)));

类型脚本类:

class Animal {
}

class Snake extends Animal {
}

class Horse extends Animal {
}

推荐答案

如果您愿意依赖一个可能很快就会改变的功能,因为它基于过时的规范,并且如果您愿意要仅使用类而不使用接口,您可以使用装饰器来实现.

If you are willing to take a dependency on a feature which is likely to change fairly soon, as it is based on an obsolete specification, and if you are willing to use only classes and not interfaces, you can accomplish this using a decorator.

这是一个例子:

hierarchy-tracked.ts

export default function hierarchyTracked(target: new (...args: any[]) => object) {
  for (const proto of walkPrototypeChain(target)) {
    if (!Object.hasOwnProperty.call(proto, 'extendedBy')) {
      const extendedBy: typeof Function.extendedBy = [];
      Object.defineProperty(proto, 'extendedBy', {
        get: () => extendedBy
      });
    }
    // ! is used to suppress a strictNullChecks error on optional.
    // This is OK since we know it is now defined.
    proto.extendedBy!.push(target);
  }
}

declare global {
  interface Function {
    // Declared as optional because not all classes are extended.
    extendedBy?: Array<new (...args: any[]) => object>;
  }
}

function* walkPrototypeChain(target: new (...args: any[]) => object) {
  let proto = Reflect.getPrototypeOf(target);
  while (proto && proto !== Object) {
    yield proto;
    proto = Reflect.getPrototypeOf(proto);
  }
}

animals.ts

import hierarchyTracked from './hierarachy-tracked';

export class Animal {
  alive = true;
  static get slayable() {return true;}
  static extinct = false;
}

@hierarchyTracked export class Snake extends Animal {
  isEctotherm = true;
}

@hierarchyTracked export class Cobra extends Snake {
  isDeadly = true;
}

@hierarchyTracked export class Horse extends Animal {
  isEndotherm = true;
}
// logs
Animal.extendedBy && Animal.extendedBy.map(Taxon => Taxon.name)
  .forEach(name => {
    console.log(name);
  });
// Snake
// Cobra
// Horse

Snake.extendedBy && Snake.extendedBy.map(Taxon => Taxon.name)
  .forEach(name => {
    console.log(name);
  });
// Cobra

没有必要求助于全局状态,它实际上非常整洁和明确.

There is no need to resort to global state and it is actually quite tidy and explicit.

这还与Babel 7 如果你没有使用 TypeScript.(请注意,上面提到的关于装饰器使用的相同警告仍然适用)

This also works with Babel 7 if you are not using TypeScript. (note that the same caveats regarding decorator usage mentioned above still apply)

当然,如果您不想依赖装饰器,手动编写是微不足道的:

Of course this is trivial to write manually if you do not want to rely on decorators:

import trackHierarchy from './hierarachy-tracked';

export class Animal { }

class Snake extends Animal { ... }
trackHierarchy(Snake);

export {Snake};

回到上面的示例代码,很容易实现.

Back to your example code above, it is easily achieved.

它来自

var childTypes = assembly.GetTypes().Where(_ => _.IsSubclassOf(typeof(Animal)));

简单

const childClasses = Animal.extendedBy || [];

警告

如果您发现自己想要编写这样的代码,您应该退后一步,确保您确实了解 JavaScript.这种模式,实际上是您的示例用例,通常表明有人以古典思维方式接触该语言,注意到 ES 2015 类,并开始认为它们与传统语言中的类有关.

If you find yourself wanting to write code like this, you should take a step back and make sure you actually know JavaScript. This sort of pattern, and indeed your example use case, usually indicates that someone has come to the language with a classical mindset, noticed ES 2015 classes, and began to think they are related to classes in traditional languages.

ES 类与 C#、C++、Java 或 Scala 类非常相似.

ES classes could not be less like C#, C++, Java, or Scala classes.

首先:JavaScript 中的类不是类型.

First and foremost: Classes in JavaScript are not types.

JavaScript 中的类是.

Classes in JavaScript are values.

他们的声明形式基本上只是原型之上的语法糖.您试图实现的模式表明您可能不太了解这一点.特别是,它表明您可能认为它们特别.

Their declaration form is fundamentally just a syntactic sugar over prototypes. The pattern you are trying to achieve suggests you may not understand this well. In particular, it suggests that you may think that they are special.

这篇关于如何在Type Script中使用反射获取实现某个基类的子类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆