如何指定排除已知继承索引键的 class 索引签名?

How can I specify a class index signature that excludes known inherited index keys?

我想创建一个继承 class 的 class,并为父 class 中不存在的所有新 class 属性指定一个索引签名].

考虑这样一种情况,您希望为搜索查询指定某种格式,该查询可以在字段上采用搜索词数组,并且继承自一般查询 class。

class Query {
  limit = 25;
  offset?: number;
  constructor() { /* do stuff */ }
}

class FieldSearchQuery extends Query {
  [key: Exclude<string, keyof Query>]: string[]; // not valid, but captures the gist
  constructor() { super(); /* do stuff */ }
}

有替代方案吗?请注意,有一个现有的基础 class,我的目标是缩小子 class 的类型,以便它可以使用任何 new 键值因为不与父键 相交,我们应该能够类型检查与这些未知键关联的值是否属于已定义的类型(在上面的示例中,字符串数组).

我一直在查看 Advanced Types 文档,感觉好像我一定遗漏了一些东西,因为完成这个的所有工具似乎都存在。

编辑: 我刚刚想出了一个可能的改进,其中您至少可以排除父级中不存在的所有值类型:

class Query {
  limit = 25;
  offset?: number;
  constructor() { /* do stuff */ }
}

class FieldSearchQuery extends Query {
  [key: string]: Query[keyof Query]|string[]; // valid, but overly broad
  constructor() { super(); /* do stuff */ }
}

您确定这里的模式正确吗?因为如果您在 class 上指定索引签名,它不仅会在 class 属性上而且还会在所有方法上。

class B {
  [key: string]: string[]

  foo(): number { // Property 'foo' of type '() => number' is not assignable to string index type 'string[]'.
    return 1
  }
}

实现您的解决方案的一种方法是遵循打字稿文档中的 intersection types example

我的解决方案是在 class 上声明一个字段并指定其类型。

type QueryParams = { [key: string]: any } & {
  limit: number
  offset?: number
}

class Query<T extends QueryParams> {
  params: T
  constructor(params: Partial<T>) {
    this.params.limit = params.limit === undefined ? 25 : params.limit
  }
}

type FieldSearchQueryParams = { [key: string]: string[] } & {
  limit: number
  offset?: number
}

class FieldSearchQuery extends Query<FieldSearchQueryParams> {
  constructor(params: Partial<FieldSearchQueryParams>) {
    super(params)
    // do stuff
  }
}