可以捕获提供给泛型类的运行时类型吗?

时间:2020-01-05 22:38:28

标签: typescript

我正在为SortedMap<string, T>类型的对象编写一个序列化程序,并且我在序列化一个实例时使用T的实际名称填充该对象(以简化反序列化逻辑);

我想以某种方式在构造函数中执行此操作,但是我看不到可以在构造函数中调用“ T”的方法。像这样吗?

  class Foo {
    ...
  }

  class SortedMap<T> {
     memberTypeName : string;

     constructor() {
       this.memberTypeName = [some "type of T" function from which I can get the name?]
     }

     get(key: string) : T { ... }
     add(key: string, item: T) {...}
  }

  let foos = new SortedMap<Foo>();
  console.log(`This map contains ${foos.memberTypeName}s`);


  >This map contains Foos 

我以为T可能有一些方法可以让我对它表示的Type进行某种类型的反射,或者实例化T并从实例中获取其类型,但是VS Code中的intellisense没有任何意义根本没有建议,let foo = new T();也不起作用(而且我猜想T需要具有无参数的构造函数)

我考虑过使用一个接口,该接口要求T实现knowsItsOwnName类的属性,但是这意味着我将无法在我自己没有编写的类上使用它。另一个想法是,也许我可以在调用get时在某种代理中询问T类型,但这似乎还有很长一段路要走。

2 个答案:

答案 0 :(得分:2)

由于将代码编译为JavaScript时类型系统为erased,因此在运行时没有<form>。如果要使用表示T类型名称的字符串初始化SortedMap<T>的实例,则必须将该字符串(或可以产生该字符串的东西)传递给其构造函数。例如,假设您的目标JavaScript运行时与ES2015或更高版本兼容,则可以将T的构造函数传递到T的构造函数中,并利用类构造函数和函数具有{ {3}},就像这样:

SortedMap<T>

这几乎可以为您提供所需的行为:

class SortedMap<T> {
  memberTypeName: string;

  constructor(ctor: (new (...args: any) => T)) {
    this.memberTypeName = ctor.name;
  }

  get(key: string): T { /* impl */ return null! }
  add(key: string, item: T) { /* impl */ }
}

请注意,您不需要在let foos = new SortedMap(Foo); foos.add("blorp", new Foo()); console.log(`This map contains ${foos.memberTypeName}s`); // This map contains Foos let dates = new SortedMap(Date); dates.add("today", new Date()); console.log(`This map contains ${dates.memberTypeName}s`); // This map contains Dates T中手动指定new SortedMap(Foo)参数,因为编译器可以从new SortedMap(Date)的实例类型中推断出该参数。和Foo构造函数。


无论如何,希望能有所帮助;祝你好运!

name property

答案 1 :(得分:0)

没有简单的方法可以用语法实现所需的功能。 Since interface information is not available in runtime.

[You probably can write some plugin for your TypeScript compiler which will do it for you. I don't know limitations there]

但是最实用的方法是做以下两件事之一:

1。您可以创建第一个参数为通用类型的地图:

    let foos = new SortedMap(Foo);

然后在您的构造函数中,您可以访问

    Foo.name 

但是如果您使用类而不是接口,那将起作用。将字符串传递给构造函数将执行类似的工作,但是将使其重构,尽管它可以与任何接口和类一起使用。

2。当您的地图中至少有一个对象时。您也可以尝试获得所需的东西

    firstFooObjectInMap.constructor.name

但是如果您只有对象文字而没有构造函数属性,那可能就不那么安全了。

然后,您可以编写自己的创意反射功能,该功能将打印带有控制台键的对象结构。如果您使用对象文字和接口,并且不想向构造函数添加额外的参数,则可以选择这种方法