【问题标题】:Typescript, interface, type, multiple optional properties, property conditioned on other propertyTypescript、接口、类型、多个可选属性、以其他属性为条件的属性
【发布时间】:2023-04-08 20:26:01
【问题描述】:

如果存在updatedBy 属性,我需要一个需要属性updatedAt 的接口或类型(反之亦然);但是,它应该不允许设置任何属性。

interface BaseRow {
    id: string
    createdAt: string
    createdBy: string
}

interface Updated {
    updatedAt: string
    updatedBy: string
}

interface UpdatedRow extends BaseRow, Updated {}

type Row = BaseRow | UpdatedRow

基于上述情况,我预计以下内容会导致打字稿编译器抛出错误,因为updatedAt 存在但updatedBy 不存在。

const x: Row = {
    id: 'someID',
    createdAt: 'someISO',
    createdBy: 'someID',
    updatedAt: 'someISO'
}

以上内容不会引发任何错误。

为什么上述解决方案没有按预期工作?实现有条件地需要两个或更多属性的interfacetype 的最佳方法是什么?

Typescript Playground

【问题讨论】:

  • 在我看来,TS 可能只是认为x 只是一个带有额外updatedAt 属性的Row 类型,而不是UpdatedRow 类型..
  • @aznbanana9 这没有意义,因为如果添加未知属性,编译器仍然会抛出错误,但不会为 updatedAtupdatedBy 抛出错误

标签: typescript types interface


【解决方案1】:

根据对对象literals实施严格检查的PR,执行的检查是:

...对象字面量指定目标类型中不存在的属性是错误的

虽然属性位于联合类型的不同分支上,但该属性存在于联合类型上。由于另一个更新的属性不存在,对象字面量不符合UpdatedRow 接口,但它确实符合Row 接口,因此它可以分配给变量。这就是没有错误的原因。

一种解决方案(可能适用于您的情况,也可能不适用)是通过在两个接口上添加一个类型为不同字符串文字类型的字符串属性来确保更新的行与未更新的行不兼容:

interface BaseRow {
    id: string
    createdAt: string
    createdBy: string
}

interface Updated {
    type: 'u'
    updatedAt: string
    updatedBy: string
}

interface UpdatedRow extends BaseRow, Updated {}

type Row = (BaseRow & { type: 'n'})  | UpdatedRow

const x: Row = { // Error, no updatedBy
    type: 'u',
    id: 'someID',
    createdAt: 'someISO',
    createdBy: 'someID',
    updatedAt: 'someISO'
}

const x2: Row = { // Error, with updatedAt is not assignable to (BaseRow & { type: 'n'}) 
    type: 'n',
    id: 'someID',
    createdAt: 'someISO',
    createdBy: 'someID',
    updatedAt: 'someISO'
}

【讨论】:

  • 感谢您的回答。我以为我在问一个简单的问题,并且有一些直接的方法可以实现。似乎应该有更好的方法,我很惊讶 tsc 不支持这种相当常见的场景。在可能的情况下,将 updatedByupdatedAt 组合到同一属性 updated?: { by: string, at: string } 甚至可能更可取地更改运行时数据的结构。我将再给它 48 小时,如果没有人有更好的主意,我会接受这个答案。
  • @RichardForrester 10x,是的,这似乎是一个常见的场景,但我认为这是 ts 团队深思熟虑的决定,我检查了该场景的代码和处理,专门测试了该属性是否在我同意联合中的任何类型都不理想
  • @RichardForrester 我找到了解决这个问题的方法,你可以在这里找到它:stackoverflow.com/questions/48827802/…
猜你喜欢
  • 2020-09-14
  • 2016-02-23
  • 2020-02-07
  • 1970-01-01
  • 1970-01-01
  • 2021-05-16
  • 1970-01-01
  • 2020-06-26
相关资源
最近更新 更多