Bai*_*aig 5 reflection typescript
我们可以像C#一样在Type Script中使用反射来获取实现某个基类的类列表吗?
例如,假设Snake and Horse实现了基类Animal.现在我需要获得实现Animal的类.与我们在C#中可以做的类似:
C#等效代码:
var childTypes = assembly.GetTypes().Where(_ => _.IsSubclassOf(typeof(Animal)));
Run Code Online (Sandbox Code Playgroud)
键入脚本类:
class Animal {
}
class Snake extends Animal {
}
class Horse extends Animal {
}
Run Code Online (Sandbox Code Playgroud)
如果你愿意依赖一个可能很快就会改变的特性,因为它基于一个过时的规范,如果你愿意只使用类而不使用接口,你可以使用装饰器来实现这一点。
下面是一个例子:
层次跟踪.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);
}
}
Run Code Online (Sandbox Code Playgroud)
动物.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
Run Code Online (Sandbox Code Playgroud)
没有必要求助于全局状态,它实际上非常整洁和明确。
如果您不使用 TypeScript,这也适用于Babel 7。(请注意,上面提到的关于装饰器使用的相同警告仍然适用)
当然,如果您不想依赖装饰器,那么手动编写是微不足道的:
import trackHierarchy from './hierarachy-tracked';
export class Animal { }
class Snake extends Animal { ... }
trackHierarchy(Snake);
export {Snake};
Run Code Online (Sandbox Code Playgroud)
回到上面的示例代码,很容易实现。
它来自
var childTypes = assembly.GetTypes().Where(_ => _.IsSubclassOf(typeof(Animal)));
Run Code Online (Sandbox Code Playgroud)
简单地
const childClasses = Animal.extendedBy || [];
Run Code Online (Sandbox Code Playgroud)
警告
如果您发现自己想要编写这样的代码,您应该退后一步,确保您确实了解 JavaScript。这种模式,实际上是您的示例用例,通常表明有人以经典的思维方式接触该语言,注意到 ES 2015 类,并开始认为它们与传统语言中的类有关。
ES 类与 C#、C++、Java 或 Scala 类非常相似。
首先也是最重要的:JavaScript 中的类不是类型。
JavaScript 中的类是值。
它们的声明形式基本上只是原型之上的语法糖。您试图实现的模式表明您可能不太了解这一点。特别是,它表明您可能认为它们很特别。
一种方法是跟踪您在一个全局数组中创建的所有类:
var allClasses = []
function register(c) {
allClasses.push(c);
}
register(class Animal {});
register(class Snake extends Animal {});
register(class Horse extends Animal {});
register(class Car {});
Run Code Online (Sandbox Code Playgroud)
当您需要从特定类继承的类时,只需过滤掉您想要的类:
Object.values(allClasses).filter((c) => Animal.isPrototypeOf(c))
Run Code Online (Sandbox Code Playgroud)
该解决方案并非特定于 Typescript,它也适用于纯 JavaScript。
| 归档时间: |
|
| 查看次数: |
2628 次 |
| 最近记录: |