【问题标题】:typescript generic constraint keyof T and string: ts2322typescript 通用约束 keyof T 和字符串:ts2322
【发布时间】:2021-05-21 18:56:14
【问题描述】:

我正在尝试编写一个泛型类,它保留一对指向泛型类型键的特殊指针。这是这个 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 的子类型怎么不能分配给这种类型?有什么方法可以表达这个约束吗?

【问题讨论】:

  • 考虑const z: 'foo' &amp; string = 'id'; - 这不起作用,因为'id'不能分配给'foo',所以如果你用'id'以外的键传递一些T,你会遇到同样的问题.至于“有没有办法表达这种约束?” - 不是 100% 确定你在这里尝试做什么。我认为您使用 'id' 作为默认键的设计点,而不对 T 的形状做出假设会导致打字混乱。也许您可以添加一些用法示例,什么应该起作用,什么不应该等等,我可以进一步提供帮助
  • 我不太明白。 Tid 需要是T 的键,所以T 不能是'foo',否则Tid 将没有可能的类型。不是使用keyof 强制T 成为对象吗?

标签: typescript typescript-generics


【解决方案1】:

我认为问题在于 Typescript 并不真正支持相同值的不同类型(例如,idKey),这取决于是否从调用方(Tidundefined)查看值或从实施者的角度来看(Tid"id")。有类似的问题,如 microsoft/TypeScript#42053 提交为错误,但我不确定它们何时会得到解决。

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


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

  constructor({
    idKey, sortKey,
  }: BaseStoreConfig<T, Tid, Tsk>) {
    this[_idKey] = idKey ?? "id" // okay
    this[_sortKey] = sortKey
  }

现在一切都编译成功了。

Playground link to code

【讨论】:

    猜你喜欢
    • 2021-01-25
    • 1970-01-01
    • 2021-11-21
    • 2020-02-28
    • 2011-02-27
    • 2021-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多