Typescript 嵌套标记/区分联合类型

标签 typescript

假设我有以下类型(语法类似于 Elm/Haskell):

type Reply = LoginReply | LogoutReply
type LoginReply = LoginSucceeded | AlreadyLoggedIn String

如果我尝试使用 Typescript 的可区分联合对其进行建模,我将面临以下问题:LoginReply 需要具有值为“loginReply”的属性 kind,但它可以不是因为它是使用 type 关键字声明的,而不是 class

这是迄今为止我解决这个问题的最佳方法:

type Reply = LoginReply | LogoutReply

type LoginReply = LoginSucceeded | AlreadyLoggedIn

interface LoginSucceeded {
  kind: "loginSucceeded";
}

interface AlreadyLoggedIn {
  kind: "alreadyLoggedIn";
  loggedInUsername: string;
}

interface LogoutReply {
  kind: "logoutReply";
}

如您所见,人们甚至不能在任何地方使用“loginReply”,因此不能用于歧视。

要知道 Reply 变量是 LoginReply,我唯一的解决方法是查看其 kind 是否是 之一”登录成功”“alreadyLoggedIn”

那么,我如何在 Typescript 中实现我想要的目标呢? 如何创建一个可区分联合类型,其子类型本身就是可区分联合类型?

最佳答案

因为 LoginReply 只是 LoginSucceeded | 的联合。 AlreadyLoggedIn,从类型系统的角度来看,type Reply = LoginReply | 之间没有区别。 LogoutReplytype Reply = LoginSucceeded |已经登录 |注销回复type 关键字引入了一个类型别名,顾名思义,它只是类型的一个方便名称,本身并不是一个新类型。

你有两个选择,但都不是 100% 你想要的。

您可以检查 LoginReply 的所有可能值 kind,正如您提到的您考虑的那样:

function doStuff(o: Reply) {
    switch(o.kind)
    {
        case 'alreadyLoggedIn' : 
        case 'loginSucceeded' : 
            o; /* is LoginReply */ break;
        case 'logoutReply': o // o is  LogoutReply
    }
} 

或者您可以为 LoginReply 子类型添加额外的 subKind 字段:

export type Reply = LoginReply | LogoutReply

type LoginReply = LoginSucceeded | AlreadyLoggedIn

interface LoginSucceeded {
    subKind: "loginSucceeded";
    kind: "loginReply";
}

interface AlreadyLoggedIn {
    kind: "loginReply";
    subKind: "alreadyLoggedIn";
    loggedInUsername: string;
}

interface LogoutReply {
    kind: "logoutReply";
    logout: boolean
}

function doStuff(o: Reply) {
    switch(o.kind)
    {
        case 'loginReply' : o // is LoginReply
            switch(o.subKind) {
                case 'alreadyLoggedIn' : o; /* is AlreadyLoggedIn */ break;
                case 'loginSucceeded' : o; /* is LoginSucceeded */ break;
            }
            break;
        case 'logoutReply': o // LogoutReply
    }
} 

关于Typescript 嵌套标记/区分联合类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51744218/

相关文章:

javascript - 如何在 Angular 中按日期字符串(昨天、今天、本月、上个月)进行过滤

typescript - tsconfig.json 的 baseUrl 不起作用

javascript - moment-duration-format.d.ts 定义不扩展力矩模块

javascript - 类型 'userAgentData' 上不存在属性 'Navigator'

javascript - javascript 中缺少 typescript 声明文件

javascript - Angular 6 - 更改变量但不刷新 View

javascript - 为什么这个 typescript 程序永远不会结束?

angular - 有没有办法忽略 Angular 生命周期方法的 "Missing return type on function"?

javascript - "[index : string]": IFoo notation in typescript

angular - 如何在 Angular 5 中的 Angular Material Snackbar 中添加图标