检测泛型类型参数是否具有id属性?

时间:2018-08-31 23:42:41

标签: javascript typescript generics generic-programming

我正在设计一个通用的Slice<E>类,该类表示一组实例的一部分实例。例如,如果我们有Todo个实例,则切片可以代表所有已完成的实例。

如果Todo类具有id属性,我们想在hasID实例上将true设置为Slice,以便我们也可以建立索引Slice的{​​{1}}实例。有没有一种方法可以在运行时检测泛型参数是否具有和id属性?

1 个答案:

答案 0 :(得分:1)

没有代码,这里没有太多可以继续的事情了。

从表面上看:不,您不能在运行时分析泛型类型参数,因为类型系统为erased。在运行时,您只能分析运行时值,例如传递给构造函数的实际对象。在编译时,您可能可以使编译器根据通用类型参数为true提供特定的falsehasID布尔文字类型。您可以同时做这两种事情,并希望您有一个解决方案,其中运行时值实际上与编译时类型匹配。

让我们尝试一下。这是一个可能的解决方案的草图:

class Slice<E> {
  instances: E[]
  hasID: E extends {id: any} ? true : false;
  constructor(firstInstance: E, ...restInstances: E[]) {
    this.hasID = 'id' in firstInstance as Slice<E>['hasID'];    
    this.instances = [firstInstance, ...restInstances];
  }
}

hasID属性提供了一个conditional type,该属性评估E类型的参数,如果存在true则返回E['id'],否则返回false

构造函数接受至少一个类型为E的参数,在运行时分析其中的第一个参数id以设置hasID的运行时间值。

让我们看看它是否有效:

const sliceOne = new Slice({a: 1}, {a: 2});
sliceOne.hasID // false at compile time and runtime

const sliceTwo = new Slice({id: 1}, {id: 2});
sliceTwo.hasID // true at compile time and runtime

看起来不错。仍然有些边缘情况您可能需要担心,例如:

declare const notSure: object;
const oopsie = new Slice(notSure);
oopsie.hasID; // false at compile time, maybe true at runtime!

编译器无法验证object是否具有id属性,因此它为hasID提供类型false。但是,当然object 可能具有id属性,因此hasID可能在运行时为true。有办法解决吗?也许。但这并不简单。问题是您是否有可能遇到这些情况以及您是否关心它们。

无论如何,希望这有意义并给您一些指导。祝你好运!