【问题标题】:Typescript keyof overlap of Partial部分重叠的打字稿键
【发布时间】:2020-09-26 13:12:59
【问题描述】:

我想输入一个允许默认值的数据库插入函数: (我正在使用 type-fest 的 SetOptional)

function defaultInsert<T, D = Partial<T>>(data: SetOptional<T, keyof D>, defaults: D) {

我想对 SetOptional 说的是,数据对象应该包含 T 中的任何内容,而不是在默认值 (D) 中指定,但它可以覆盖默认值中的任何内容。

不幸的是,这导致了以下错误

Type 'keyof D' does not satisfy the constraint 'keyof T'.
  Type 'string | number | symbol' is not assignable to type 'keyof T'.
    Type 'string' is not assignable to type 'keyof T'.(2344)

Typescript playground 获取更详细的示例。

有什么方法可以过滤 Partial 以仅包含 T 的键,因为我假设这是由于 D 可能包含不在 T 中的多余属性而导致的问题?

非常感谢

编辑:作为@Alex Chashin 的建议,另一个 TS Playground 使用键作为定义默认值的方式。

EDIT2:使用 UPD2 @Alex Chashin 中提供的解决方案更新了 playground

EDIT3:更新了前面的示例,以便也可以省略默认值:playground

【问题讨论】:

    标签: typescript keyof


    【解决方案1】:

    UPD2: 所以我唯一能想到的,在这个世界上存在并不太复杂的就是这个(ts playground):

    function defaultInsert<T, D extends keyof T>(
      data: Omit<T, D> & Partial<Pick<T, D>>,
      defaults: Pick<T, D>
    ): void {
      // Hover over this variable to see its type
      const doc = { ...data, ...defaults } as T
      insert<T>(doc)
    }
    

    这通过了您提供的测试,但不幸的是 {...data, ...default} 未被推断为 T,因此您必须强制转换它。不过我认为这没什么大不了的,因为这种类型转换只需要 4 个符号。唯一的问题是您必须每次都明确地为D 提供密钥,因为您需要在示例中编写keyof typeof personDefaults 升级版: 使用一种可能的解决方案链接到 TS 游乐场:playgroung

    原答案:

    所以Partial&lt;T&gt; 已经使T 的所有键成为可选的,你不需要在你做了Partial 之后使用SetOptional。如果您希望 所有 数据键是可选的,请使用:

    function defaultInsert<T>(data: Partial<T>, defaults: T) {
      // ...
    }
    

    注意defaults 的类型为T,而不是Partial&lt;T&gt;,因为如果它是Partial&lt;T&gt;,您可以提供不完整的文档data 和不完整的文档defaults,所以合并它们不会提供完整的文档,这对您来说可能是个问题。如果不是,请将T 替换为Partial&lt;T&gt;,很难判断,因为您没有提供所有代码。

    如果您只希望某些键是可选的,请执行以下操作:

    function defaultInsert<T, Keys extends string>(
      data: SetOptional<T, Keys>, 
      defaults: { [key in Keys]: T[key] }
    ) {
      // ...
    }
    

    像这样,您只需为可选键提供默认值,而不是为所有键提供默认值 您也可以将defaults 设为

    Omit<Partial<T>, Keys> & { [key in Keys]: T[key] }
    // or if you use your `SetOptional`
    SetOptional<T, Exclude<keyof T, Keys>>
    

    因此,当您为非可选键提供默认值时,打字稿不会抱怨

    然后使用like

    defaultInsert<{ foo: number, bar: string }, 'foo'>(
      { bar: 'abc' },
      { foo: 12345 }
    )
    

    【讨论】:

    • 至于您的第一段,我想将 D 中提供的键设置为 T 中的可选键,其中 D 是 T 的一部分。我确实希望仅默认 T 的某些字段,因此是可选的在数据中。正如您在操场链接中看到的那样,我试图从 D 的类型中推断出哪些。我可能误解了你最后的例子,因为尝试它总是出错(见主帖中的编辑)
    • @EvertEtienne,在我更新的答案中检查指向 ts playground 的链接,当您调用函数时它不会显示错误,但它也不会推断 { ...data, ...defaults } 的类型,我我会尝试弥补一些更好的东西,如果我找到不同的解决方案,我会通知你
    • @EvertEtienne 所以我放了一个指向另一个选项的链接,它基本相同但看起来更好,但我现在无法想出更好的东西
    • 非常感谢。您的链接似乎对我不起作用,但我已经用游乐场更新了我的帖子,显示了您的第二次更新。它似乎确实有效,可惜需要演员阵容,因为它似乎应该能够被推断出来。
    猜你喜欢
    • 1970-01-01
    • 2018-12-21
    • 2021-02-05
    • 1970-01-01
    • 2021-09-22
    • 2020-12-20
    • 1970-01-01
    • 2020-04-13
    • 2021-06-10
    相关资源
    最近更新 更多