打字稿嵌套标记/区分联合类型

时间:2018-08-08 10:18:36

标签: typescript

假设我有以下几种类型(语法为Elm-ish / Haskell-ish):

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"loginSucceeded""alreadyLoggedIn"之一。 / p>

那么,如何实现Typescript中想要的功能? 如何创建其子类型为歧视联合类型的歧视联合类型?

2 个答案:

答案 0 :(得分:2)

由于<div class="col-lg-4"> <div class="panel-group" id="duyuruGosterme"> <div class="panel"> @foreach (var item in Model) { <div class="panel-heading bg-blue-800"> <h6 class="panel-title"> <a data-parent="#duyuruGosterme" data-toggle="collapse" href="#@item.ID">@item.Baslik <span class="pull-right label label-flat label-rounded border-white">@item.YayinTarihi.ToString("dd MM yyyy")</span></a> </h6> </div> <div id="@item.ID" class="panel-collapse collapse"> <div class="panel-body"> <p>@Html.Raw(item.icerik)</p> </div> </div> } </div> </div> </div> 只是LoginReply的并集,因此从类型系统角度来看,LoginSucceeded | AlreadyLoggedIntype Reply = LoginReply | LogoutReply之间没有区别。 type Reply = LoginSucceeded | AlreadyLoggedIn | LogoutReply关键字引入了类型别名,顾名思义,该别名只是该类型的一个方便的名称,而不是其本身的新类型。

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

您可以按照自己的意愿查看type中所有可能的值kind

LoginReply

或者您可以为function doStuff(o: Reply) { switch(o.kind) { case 'alreadyLoggedIn' : case 'loginSucceeded' : o; /* is LoginReply */ break; case 'logoutReply': o // o is LogoutReply } } 子类型添加一个额外的subKind字段:

LoginReply

答案 1 :(得分:1)

对于所有解决方案,都将保留此答案。请更新,如果您还有其他解决方案。


解决方案#1 :如问题所述,请查看kind是否为"loginSucceeded""alreadyLoggedIn"之一。


解决方案2 :如Titian Cernicova-Dragomirhis answer中所述,请使用kindsubKind


解决方案#3

如果有人争辩说 Solution#2 使LoginSucceededAlreadyLoggedIn对被歧视的类型了解得太多,那么人们也可以争辩说,即使在一种情况下歧视程度,他们不应该了解kind。如果有人遵循该论点,则可以实现这样的解决方案:

type Reply = { kind: "loginReply", t: LoginReply } | { kind: "logoutReply", t: LogoutReply }

type LoginReply = { kind: "loginSucceeded", t: LoginSucceeded } | { kind: "alreadyLoggedIn", t: AlreadyLoggedIn }

interface LoginSucceeded {
}

interface AlreadyLoggedIn {
    loggedInUsername: string;
}

interface LogoutReply {
    logout: boolean
}

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