打字稿通用约束键 T 和字符串:ts2322

时间:2021-02-18 19:00:26

标签: typescript typescript-generics

我正在尝试编写一个泛型类,该类保留一对指向泛型类型键的特殊指针。这是这个 MVP 的playground example

const _idKey = Symbol('_idKey')
const _sortKey = Symbol('_sortKey')

export interface BaseStoreConfig<T, Tid extends keyof T, Tsk extends keyof T | undefined> {
  idKey?: Tid
  sortKey?: Tsk
}

export class BaseStore<T, Tid extends keyof T & string, Tsk extends keyof T | undefined> {
  public [_idKey]: keyof T | 'id'
  public [_sortKey]?: keyof T | undefined

  constructor({
    idKey = 'id', // Errors, see below
    sortKey,
  }: BaseStoreConfig<T, Tid, Tsk>) {
    this[_idKey] = idKey
    this[_sortKey] = sortKey
  }
}

这会产生一个 ts2322 错误(我已经尝试了 Tid 约束的几种变体,我总是回到这个错误)

Type 'string' is not assignable to type 'Tid'.
  'string' is assignable to the constraint of type 'Tid', but 'Tid' 
   could be instantiated with a different subtype of constraint 'string'.ts(2322)

我通常理解这个错误,但在这种情况下我很困惑。 string 的子类型如何不能分配给这种类型?有没有办法表达这个约束?

1 个答案:

答案 0 :(得分:3)

我认为问题在于 Typescript 并不真正支持相同值的不同类型(例如,idKey),这取决于值是从调用方(Tid 还是 { {1}})或来自实施者(undefinedTid)。有类似 microsoft/TypeScript#42053 之类的问题作为错误提交,但我不确定何时会得到解决。

您已将构造函数参数注释为 "id" 类型,其 BaseStoreConfig<T, Tid, Tsk> 属性的类型为 idKey。在尝试为其分配默认值 Tid | undefined 时,编译器将其视为不匹配...因为 "id" 可能无法分配给 "id"。提到 Tid 而不是专门的 string 的特定错误似乎是自 3.9 之后对 TypeScript 的一些更改(不知道为什么,但我假设它在其他地方做了合理的事情)。如果您恢复到 3.9 and look at it,您将看到明确提及 "id" 的错误。


所以我认为这里的解决方法是不要在解构中使用默认值,因为没有很好的方法来表示相同值的两种不同类型的东西。相反,让我们将默认值移动到构造函数的主体:

"id"

现在一切都编译没有错误。

Playground link to code