TypeScript:带空对象的区分联合

时间:2018-10-08 18:44:52

标签: javascript typescript discriminated-union

我有以下类型的update msg model = case msg of UrlRequested (Browser.Internal _) -> ( model, Cmd.none ) UrlRequested (Browser.External "") -> ( model, Cmd.none ) UrlRequested (Browser.External url) -> ( model, Browser.Navigation.load url ) UrlChanged _ -> ( model, Cmd.none )

User

因此,从本质上讲,用户可以是具有名称和电子邮件属性的对象,也可以是空对象。

当我尝试检查给定用户对象的两个中的 时,TypeScript显示错误。

type User = {
    name: string;
    email: string;
} | {};

具体来说,以上代码会引发错误:

if (user.name) { // ERROR
    // do something if user object is populated
}

是否有可能存在一个区分联合,其中接口之一是空对象?

2 个答案:

答案 0 :(得分:1)

有区别的联合(在TypeScript中通常理解为该术语)是这样一种联合,其中在联合的每个成员上都有一个具有不同值的 discriminant 属性。因此,根据定义,包含{}的联合不是歧视性联合。如果您愿意将设计更改为使用有区别的联合,那么一切都会正常。

当前的设计:通常,TypeScript对象类型包括具有至少个指定属性的任何对象。这意味着{}实际上是任何对象的类型,而您的User的类型只是简化为{}。没有(合理的)方式来表达没有属性的对象的类型。 this suggestion可能要加一个。您必须先投射对象,然后才能测试name属性,即使您测试了该属性,我也不知道有什么方法可以使TypeScript自动知道email属性存在。您至少可以定义一个user-defined type guard以将所有混乱隐藏在一个函数中。

答案 1 :(得分:1)

您可以in https://www.typescriptlang.org/docs/handbook/advanced-types.html#using-the-in-operator

if (user.name) { // error
    user // typeof user is User | {}
    user.name // error
    user.email // error 
}

if ('name' in user) {
    user // ok, typeof user is User
    user.name  // string 
    user.email // string
}

tsplayground