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

Detecting whether a generic type argument has an id property?

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

如果 Todo class 有一个 id 属性 我们想在 [=17] 上将 hasID 设置为 true =] 实例,这样我们也可以通过 id 索引 Slice 实例。有没有办法在运行时检测泛型参数是否有和 id 属性?

没有代码,这里没有太多内容可以继续。

从表面上看:不,您不可能在 运行 时分析泛型类型参数,因为类型系统是 erased。在 运行time 你只能分析 运行time 值,例如你传递给构造函数的实际对象。在编译时,您可以让编译器根据泛型类型参数将特定的 truefalse 布尔文字类型赋予 hasID。您可以做这两件事,并希望您有一个 运行time 值实际上与编译时类型匹配的解决方案。

我们来试试吧。这是一个可能的解决方案的草图:

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 类型参数和 returns 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 在 运行时间。有办法解决这个问题吗?可能是。但这并不简单。问题是你有多大可能 运行 进入这些案例,以及你是否关心它们。

无论如何,希望这有道理并能给你一些指导。祝你好运!