【问题标题】:Typescript discriminated unions in an object depending on string打字稿根据字符串区分对象中的联合
【发布时间】:2021-04-09 05:25:53
【问题描述】:

我最初认为我的问题可以通过条件类型来解决,但经过进一步检查,区分联合似乎更适合我的情况。

These examples 非常接近我想要的,但我仍然对如何在我的真实示例中实现它感到困惑。

假设我有一个接口,在这种情况下是我使用 Passport.js 登录后返回的数据:

export interface UserInterface {
  id: number
  username: string
  photos: {
    values: string
  }[]
  provider: 'twitter' | 'github'
  _json: TwitterProfileInterface | GithubProfileInterface
}

在上面,idusernamephotos 都是可以互换的。但是,_json 的类型取决于provider 的值。所以如果providertwitter,那么_json 就是TwitterProfileInterface

有没有什么方法可以让 Typescript 自动完成?

编辑:示例代码:

我正在运行一个 switch 语句来检查我收到的用户配置文件类型:

const user = {
  id: 1,
  username: "User",
  photos: [],
  provider: "twitter",
  _json: {
    // a bunch of data specific to the "twitter" provider
  }
};

switch(user.provider){
  case 'twitter':
    // this case will give types from both TwitterProfileInterface and GithubProfileInterface
    break;
  case 'github':
      // this case will give types from both TwitterProfileInterface and GithubProfileInterface
    break;
}

即使我有一个 switch 语句,但我用于 switch 的值包含在 TwitterProfileInterfaceTwitterProfileInterface 之外,那么这两种情况都将包括这两种类型,从而使我的类型毫无意义。

【问题讨论】:

  • 我在这里看不到条件类型的用处;这看起来更像你需要一个discriminated union,例如this。这能满足你的需求吗?如果是这样,您是否可以编辑问题以消除对条件类型的依赖?如果没有,您能否在问题中详细说明这些需求是什么?祝你好运!
  • @jcalz 这看起来更像是我想要做的,但我该如何做才能在我的工会之外决定类型?
  • 对不起,我不明白这个问题。 “类型是在我的工会之外决定的”是什么意思?你能告诉我minimal reproducible example吗?
  • OP中的例子还不够吗?在我的情况下,与 Typescript 示例不同,“开关”(provider)不包含在我正在切换的两种类型中。因此,虽然我可以使用带有 provider 的 Switch 语句,但我看不出这会对我使用的 _json 类型产生什么影响。
  • 对别人来说可能就够了,但对我来说,对不起。理想情况下,您应该使用有问题的switch 语句编写一些示例代码,这样我就可以亲眼看到您遇到了什么问题。如果您使用this union,您在编写什么具体代码时遇到问题?

标签: typescript


【解决方案1】:

使用条件类型和参数,像这样:

interface TwitterProvider { foo: number }
interface GithubProvider { foo: string }

export type UserInterface<P extends 'twitter' | 'github'> = {
  id: number
  username: string
  photos: {
    values: string
  }[]
  provider: P
  _json: P extends 'twitter' ? TwitterProvider : P extends 'github' ? GithubProvider : {}
}

let foo: UserInterface<'twitter'> = {
  id: 1,
  username: 'foo',
  photos: [{values: 'foo'}],
  provider: 'twitter',
  _json: { foo: 1 }
}

Live, Interactive Example

【讨论】:

  • 这对界面有什么作用?如果我将其粘贴在 PassportUserInterface 中,Typescript 会抛出错误
  • 噢噢噢,我现在明白这是怎么回事了。这真的很有帮助!
  • 如果要添加回退,请将: {} 更改为: FallbackType。要添加更多选项,请添加另一个链并更改 extends '...' | '...' 指令。
猜你喜欢
  • 2021-08-03
  • 2018-04-28
  • 2021-06-20
  • 1970-01-01
  • 2020-08-22
  • 2019-01-15
  • 2019-08-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多