从typescript中的属性值推断对象类型

发布于 2025-02-06 20:29:35 字数 711 浏览 1 评论 0 原文

我在打字稿中有以下代码(简化),

interface TimeoutOption {
  category: 'timeout'
  time: number
}

interface UserOption {
  category: Parameters<typeof addEventListener>[0]
}

type MyDelayOptions = Array<TimeoutOption | UserOption>


function delay(options: MyDelayOptions) {
  for (const option of options) {
    if (option.category === 'timeout') {
      timeout = setTimeout(() => {
        // not relevant
      }, option.time) // need to cast and do (option as TimeoutOption) to not get an error
    }
  }
}


以避免汇编错误,我必须添加评论中提到的类型断言。对于人类,尽管很明显,如果类别'timeout'我的 option 是类型 timeoutoption 。如果没有类型的断言,我该如何使这项工作?欢迎完整的重构。

I have the following code in Typescript (simplified)

interface TimeoutOption {
  category: 'timeout'
  time: number
}

interface UserOption {
  category: Parameters<typeof addEventListener>[0]
}

type MyDelayOptions = Array<TimeoutOption | UserOption>


function delay(options: MyDelayOptions) {
  for (const option of options) {
    if (option.category === 'timeout') {
      timeout = setTimeout(() => {
        // not relevant
      }, option.time) // need to cast and do (option as TimeoutOption) to not get an error
    }
  }
}


In order to avoid a compilation error I have to add the type assertion mentioned in the comment. For a human though it is clear that if the category is 'timeout' my option is of type TimeoutOption. How can I make this work without the type assertion? Complete refactors welcome.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

任谁 2025-02-13 20:29:35

问题在于 userOption 类别定义为 string (间接,但这就是它的出现)。结果,如果(option.category ==='timeout')不区分您的两个工会成员,因为 userOption 可以轻松地具有类别: “超时” 就像 timeoutoption 也是如此。判别(<代码>类别)必须明确区分联盟,但在您的情况下并非如此。

您可以测试 time 而不是(请参阅下面的 *** ):

function delay(options: MyDelayOptions) {
  for (const option of options) {
    if ("time" in option) { // ***
      const timeout = setTimeout(() => {
        // not relevant
      }, option.time) // need to cast and do (option as TimeoutOption) to not get an error
    }
  }
}

Playground link

The problem is that UserOption defines category as type string (indirectly, but that's what it comes out as). As a result, if (option.category === 'timeout') doesn't discriminate between your two union members, because UserOption could easily have category: "timeout" just like TimeoutOption does. The discriminant (category) has to clearly discriminate the union, but it doesn't in your case.

You could test for the presence of time instead (see *** below):

function delay(options: MyDelayOptions) {
  for (const option of options) {
    if ("time" in option) { // ***
      const timeout = setTimeout(() => {
        // not relevant
      }, option.time) // need to cast and do (option as TimeoutOption) to not get an error
    }
  }
}

Playground link

千里故人稀 2025-02-13 20:29:35

看来您需要在此处使用一个典型的函数来确认 option 是类型 timeoutoption

https://www.typescriptlang.orgg/docs/handbook/handbook/handbook/adbook/advanced-tepes-.- html

这样的事情应该做到。

function isTimeout(option: TimeoutOption | UserOption): option is TimeoutOption {
  return (option as TimeoutOption).time !== undefined;
}

...

if (itTimeout(option) {
 // do stuff
}

Playground link

Looks like you need a typeguard function here to confirm that option is of type TimeoutOption.

https://www.typescriptlang.org/docs/handbook/advanced-types.html

Something like this should do it.

function isTimeout(option: TimeoutOption | UserOption): option is TimeoutOption {
  return (option as TimeoutOption).time !== undefined;
}

...

if (itTimeout(option) {
 // do stuff
}

Playground link

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文