【问题标题】:Intersection of Discriminated Union Types可区分联合类型的交集
【发布时间】:2019-04-26 10:49:00
【问题描述】:

我正在尝试创建可区分联合类型的交集。在尝试了许多不同的方法之后,我发现了 keyof 运算符,它似乎已经工作了。但是,当我将运算符泛化为偏函数时,它不起作用。

class Account { ... }
type ILoggedIn =
  | { isLoggedIn: boolean; loggedInUser?: any }
  | { isLoggedIn: false; loggedInUser?: undefined }
  | { isLoggedIn: true; loggedInUser?: any }

type IInitialized =
  | { initialized: boolean; account?: undefined }
  | { initialized: false; account?: undefined }
  | { initialized: true; account?: Account }

type IContextWorks = { [K in keyof ILoggedIn]?: ILoggedIn[K] } &
  { [K in keyof IInitialized]?: IInitialized[K] }

type Partial<T> = { [P in keyof T]?: T[P] }
type IContextNotWork = Partial<ILoggedIn> & Partial<IInitialized>

const valueWorks: IContextWorks = {
  account: new Account(),
  initialized: true,
  isLoggedIn: true,
  loggedInUser: {},
}
const valueNotWork: IContextNotWork = {
  account: new Account(),
  initialized: true,
  isLoggedIn: true,
  loggedInUser: {},
}

我使用NotWork版本时遇到的错误是:

Type 'boolean' is not assignable to type 'true | undefined'.

我会假设要么两者都可以工作,要么两者都不能工作,但在这种情况下,只有一个工作。

我做错了什么?

【问题讨论】:

  • 什么是IXyaInitialized?我can't reproduce你的错误。
  • 另外,IContextWorks 不再是有区别的联合。歧视工会:{kind: "s", value: string} | {kind: "n", value: number}。不是:{kind: "s" | "n", value: string | number}。特别是像{kind: "s", value: 7} 这样的值匹配后一种类型,但不匹配前一种类型。
  • 我的理解是您正在尝试创建 9 种交集类型的联合,对吗?
  • 您可以为此使用有区别的联合,但实际上,如果您只是在寻找一个属性的存在,您不需要为它存储单独的布尔值,您可以在计算时计算该布尔值需要它...(例如,typeof value.account !== 'undefined'
  • 如果您无法在独立环境中重现该问题,那么我想您的下一步是分析您看到错误的环境并尝试找出不同之处。如果错误仅发生在某个版本的 TypeScript 或某些编译器选项中,那么这与问题相关,应该进行编辑。祝你好运!

标签: typescript


【解决方案1】:

我认为唯一可推断的合理结果如下所示。

type UnionOfIntersections =
    | { isLoggedIn: boolean; loggedInUser?: any } & { initialized: boolean; account?: undefined }
    | { isLoggedIn: boolean; loggedInUser?: any } & { initialized: false; account?: undefined }
    | { isLoggedIn: boolean; loggedInUser?: any } & { initialized: true; account?: Account }
    | { isLoggedIn: false; loggedInUser?: undefined } & { initialized: boolean; account?: undefined }
    | { isLoggedIn: false; loggedInUser?: undefined } & { initialized: false; account?: undefined }
    | { isLoggedIn: false; loggedInUser?: undefined } & { initialized: true; account?: Account }
    | { isLoggedIn: true; loggedInUser?: any } & { initialized: boolean; account?: undefined }
    | { isLoggedIn: true; loggedInUser?: any } & { initialized: false; account?: undefined }
    | { isLoggedIn: true; loggedInUser?: any } & { initialized: true; account?: Account }

而且我认为你标记为“不起作用”的内容实际上正确地产生了上述结果。

type IContextNotWork = Partial<ILoggedIn> & Partial<IInitialized>

【讨论】:

  • 有没有办法查看联合/交集的最终结果类型,或者是进行单元测试的唯一方法?
  • ts-playground。我总是先尝试那里的东西。鼠标悬停可以告诉很多有用的信息
猜你喜欢
  • 2020-02-16
  • 1970-01-01
  • 2018-11-24
  • 2020-05-07
  • 1970-01-01
  • 2013-08-04
  • 2018-10-26
  • 1970-01-01
相关资源
最近更新 更多